﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.X2D;
using Rappelz.GameServer.Network;
using Rappelz.GameServer.Network.GameClient;
using Rappelz.GameServer.Database;
using System.Threading;

namespace Rappelz.GameServer
{
    public class GameContent
    {
        public class HotSpot
        {
            public float x;
            public float y;
            public float sx;
            public float sy;
            public float radius;
            public bool bIsSquare;
            public int nQuestId;
            public bool bHasFired;
            public uint regenTime;
            public uint lastRegen;
            public int fireCount;
            public int nNeededStateId;
            public string szEnterScript = "";
            public string szExitScript = "";
        }

        public class MapLocationInfo : PolygonF
        {
            public MapLocationInfo(Pointf p1, Pointf p2, int id, int _pri) 
                : base (p1,p2)
            {
                this.location_id = id;
                this.priority = _pri;
            }

            public MapLocationInfo(List<Pointf> points, int id, int _pri)
                : base (points)
            {
                this.location_id = id;
                this.priority = _pri;
            }

            public override string ToString()
            {
                return location_id.ToString();
            }

            public int location_id;
            public int priority;

            // Function       :     public void GameContent::MapLocationInfo::MapLocationInfo(const struct GameContent::MapLocationInfo &)
            // Function       :     public void MapLocationInfo()
            // Function       :     public void GameContent::MapLocationInfo::~MapLocationInfo()
            // Function       :     public struct GameContent::MapLocationInfo & GameContent::MapLocationInfo::operator=(const struct GameContent::MapLocationInfo &)
            // Function       :     public void __local_vftable_ctor_closure()
            // Function       :     public void * __vecDelDtor(unsigned int)

        }


        public class ExpTable
        {
            public long exp;
            public int[] jp = new int[4];
        }

        public class SummonExpTable
        {
            public long normal;
            public long growth;
            public long evolve;
        }

        public class MonsterRespawnInfo
        {
            public MonsterRespawnInfo(uint _id, uint _interval, float _left, float _top, float _right, float _bottom, uint _monster_id, uint _max_num, uint _inc, bool _is_wandering, int _way_point_id)
            {
                this.left = _left;
                this.dungeon_id = 0;
                this.interval = _interval;
                this.top = _top;
                this.monster_id = _monster_id;
                this.right = _right;
                this.max_num = _max_num;
                this.bottom = _bottom;
                this.inc = _inc;
                this.id = _id;
                this.is_wandering = _is_wandering;
                this.layer = 0;
                this.way_point_id = _way_point_id;
            }

            public MonsterRespawnInfo(MonsterRespawnInfo src)
            {
                this.left = src.left;
                this.dungeon_id = src.dungeon_id;
                this.interval = src.interval;
                this.top = src.top;
                this.monster_id = src.monster_id;
                this.right = src.right;
                this.max_num = src.max_num;
                this.bottom = src.bottom;
                this.inc = src.inc;
                this.id = src.id;
                this.is_wandering = src.is_wandering;
                this.layer = src.layer;
                this.way_point_id = src.way_point_id;
            }

            public uint interval;           // 0x0
            public float left;              // 0x4
            public float top;               // 0x8
            public float right;             // 0xC
            public float bottom;            // 0x10
            public byte layer;              // 0x14
            public uint monster_id;         // 0x18
            public uint max_num;            // 0x1C
            public uint inc;                // 0x20
            public uint id;                 // 0x24
            public bool is_wandering;       // 0x28
            public int dungeon_id;          // 0x2C
            public int way_point_id;        // 0x30
        }

        public class FieldPropRespawnInfo
        {
            // UserDefinedType:   FIELD_PROP_RESPAWN_INFO
            // Function       :     public void FIELD_PROP_RESPAWN_INFO()
            public FieldPropRespawnInfo(FieldPropRespawnInfo _src)
            {
                this.nPropId = _src.nPropId;
                this.x = _src.x;
                this.y = _src.y;
                this.layer = _src.layer;
                this.fZOffset = _src.fZOffset;
                this.fRotateX = _src.fRotateX;
                this.fRotateY = _src.fRotateY;
                this.fRotateZ = _src.fRotateZ;
                this.fScaleX = _src.fScaleX;
                this.fScaleY = _src.fScaleY;
                this.fScaleZ = _src.fScaleZ;
                this.bLockHeight = _src.bLockHeight;
                this.fLockHeight = _src.fLockHeight;
                this.bOnce = _src.bOnce;
            }

            public FieldPropRespawnInfo()
            {
            }
            // Function       :     public void GameContent::FIELD_PROP_RESPAWN_INFO::FIELD_PROP_RESPAWN_INFO(int, float, float, unsigned char, float, float, float, float, float, float, float, bool, float)

            public int nPropId;
            public float x;
            public float y;
            public byte layer;
            public float fZOffset;
            public float fRotateX;
            public float fRotateY;
            public float fRotateZ;
            public float fScaleX;
            public float fScaleY;
            public float fScaleZ;
            public bool bLockHeight;
            public float fLockHeight;
            public bool bOnce;
        }

        public class WayPointInfo
        {
            // UserDefinedType:   WAY_POINT_INFO
            public int way_point_id;// Data           :     this+0x0, Member, Type: int, 
            public int way_point_type;// Data           :     this+0x4, Member, Type: int, 
            public int way_point_speed;// Data           :     this+0x8, Member, Type: int, 
            public List<ArPosition> vWayPoint = new List<ArPosition>();// Data           :     this+0xC, Member, Type: class std::vector<ArPosition,std::allocator<ArPosition> >, 
            // 
            // Function       :     public void GameContent::WAY_POINT_INFO::WAY_POINT_INFO(const struct GameContent::WAY_POINT_INFO &)
            // Function       :     public void WAY_POINT_INFO()
            // Function       :     public void GameContent::WAY_POINT_INFO::~WAY_POINT_INFO()
            // Function       :     public struct GameContent::WAY_POINT_INFO & GameContent::WAY_POINT_INFO::operator=(const struct GameContent::WAY_POINT_INFO &)
            // Function       :     public void * __vecDelDtor(unsigned int)
        }

        public class RandomPoolInfo
        {
// Function       :     public void RANDOM_POOL_INFO(int, int)
            public int quest_target_id;// Data           :     this+0x0, Member, Type: int, 
            public int level;// Data           :     this+0x4, Member, Type: int, 
        }

        public class RoamingCreatureRespawnInfo
        {
            // UserDefinedType:   ROAMING_CREATURE_RESPAWN_INFO
            // Function       :     public void ROAMING_CREATURE_RESPAWN_INFO(const int, const int, const unsigned long, const int, const float)
            public int m_eCreatureType;                 // 0x0
            public int m_nCreatureID;                   // 0x4
            public uint m_nRespawnInterval;             // 0x8
            public int m_nAngle;                        // 0xC
            public float m_nDistance;                   // 0x10

        }

        public class RegenInfo
        {
            public RegenInfo(uint t, uint lt)
            {
                tNextRegen = t;
                nLifeTime = lt;
            }

            public FieldPropRespawnInfo pRespawnInfo;// Data           :     this+0x0, Member, Type: const struct GameContent::FIELD_PROP_RESPAWN_INFO *, 
            public uint tNextRegen;// Data           :     this+0x4, Member, Type: unsigned long, 
            public uint nLifeTime;
        }
// UserDefinedType:   HUNTAHOLIC_MONSTER_RESPAWN_INFO
// Data           :     this+0x0, Member, Type: int, nID
// Data           :     this+0x4, Member, Type: struct X2D::Box<float>, bxArea
// 
// Data           :     this+0x14, Member, Type: int, nMonsterID
// Data           :     this+0x18, Member, Type: int, nCount
// Data           :     this+0x1C, Member, Type: unsigned long, nPeriod
// Data           :     this+0x20, Member, Type: bool, bWandering
// Function       :     public void HUNTAHOLIC_MONSTER_RESPAWN_INFO()
// Function       :     public struct GameContent::HUNTAHOLIC_MONSTER_RESPAWN_INFO & operator=(const struct GameContent::HUNTAHOLIC_MONSTER_RESPAWN_INFO &)
// UserDefinedType:   HUNTAHOLIC_INSTANCE_INFO
// Data           :     this+0x0, Member, Type: int, nID
// Data           :     this+0x4, Member, Type: short, nMinLevel
// Data           :     this+0x6, Member, Type: short, nMaxLevel
// Function       :     public const bool GameContent::HUNTAHOLIC_INSTANCE_INFO::IsProperLevel(const int)
// Data           :     this+0x8, Member, Type: class c_fixed<10000>, fPointAdvantage
// 
// Data           :     this+0x10, Member, Type: __int64, nRewardExp
// Data           :     this+0x18, Member, Type: int, nRewardJp
// Data           :     this+0x1C, Member, Type: int, nRewardSuccessItemCode
// Data           :     this+0x20, Member, Type: int, nRewardSuccessItemCount
// Data           :     this+0x24, Member, Type: int, nRewardFailItemCode
// Data           :     this+0x28, Member, Type: int, nRewardFailItemCount
// Data           :     this+0x2C, Member, Type: class std::vector<GameContent::HUNTAHOLIC_MONSTER_RESPAWN_INFO const *,std::allocator<GameContent::HUNTAHOLIC_MONSTER_RESPAWN_INFO const *> >, vRespawnInfo
// 
// Data           :     this+0x3C, Member, Type: class std::vector<GameContent::FIELD_PROP_RESPAWN_INFO const *,std::allocator<GameContent::FIELD_PROP_RESPAWN_INFO const *> >, vHealingPropInfo
// 
// Function       :     public void HUNTAHOLIC_INSTANCE_INFO(const struct GameContent::HUNTAHOLIC_INSTANCE_INFO &)
// Function       :     public void GameContent::HUNTAHOLIC_INSTANCE_INFO::HUNTAHOLIC_INSTANCE_INFO()
// Function       :     public void GameContent::HUNTAHOLIC_INSTANCE_INFO::~HUNTAHOLIC_INSTANCE_INFO()
// Function       :     public struct GameContent::HUNTAHOLIC_INSTANCE_INFO & operator=(const struct GameContent::HUNTAHOLIC_INSTANCE_INFO &)
// Function       :     public void * __vecDelDtor(unsigned int)
// UserDefinedType:   HUNTAHOLIC_INFO
// Data           :     this+0x0, Member, Type: int, nID
// Data           :     this+0x4, Member, Type: int, nNameID
// Data           :     this+0x8, Member, Type: __int64, tDailyBeginTime
// Data           :     this+0x10, Member, Type: __int64, tHuntingPeriod
// Data           :     this+0x18, Member, Type: __int64, tCycle
// Data           :     this+0x20, Member, Type: int, nObjectivePoint
// Data           :     this+0x24, Member, Type: int, nMaxPoint
// Data           :     this+0x28, Member, Type: unsigned int, nLobbyRegionLeft
// Data           :     this+0x2C, Member, Type: unsigned int, nLobbyRegionTop
// Data           :     this+0x30, Member, Type: unsigned int, nLobbyRegionRight
// Data           :     this+0x34, Member, Type: unsigned int, nLobbyRegionBottom
// Data           :     this+0x38, Member, Type: struct ArPosition, posLobby
// 
// Data           :     this+0x48, Member, Type: unsigned int, nDungeonRegionLeft
// Data           :     this+0x4C, Member, Type: unsigned int, nDungeonRegionTop
// Data           :     this+0x50, Member, Type: unsigned int, nDungeonRegionRight
// Data           :     this+0x54, Member, Type: unsigned int, nDungeonRegionBottom
// Data           :     this+0x58, Member, Type: struct ArPosition, posDungeon
// 
// Data           :     this+0x68, Member, Type: class std::vector<GameContent::HUNTAHOLIC_INSTANCE_INFO const *,std::allocator<GameContent::HUNTAHOLIC_INSTANCE_INFO const *> >, vInstanceInfo
// 
// Function       :     public void HUNTAHOLIC_INFO(const struct GameContent::HUNTAHOLIC_INFO &)
// Function       :     public void GameContent::HUNTAHOLIC_INFO::HUNTAHOLIC_INFO()
// Function       :     public void ~HUNTAHOLIC_INFO()
// Function       :     public struct GameContent::HUNTAHOLIC_INFO & operator=(const struct GameContent::HUNTAHOLIC_INFO &)
// Function       :     public void * __vecDelDtor(unsigned int)


        public class RandomPool
        {
// Function       :   public void RANDOM_POOL::RANDOM_POOL(const struct RANDOM_POOL &)
// Function       :   public void RANDOM_POOL(int)
            public int group_id;                                                    // 0x0
            public List<RandomPoolInfo> vInfo = new List<RandomPoolInfo>();         // 0x4
        }


        public static int g_nMapWidth = 700000;
        public static int g_nMapHeight = 1000000;
        public static int g_nRegionSize = 180;
        public static int g_currentLocationId = 0;
        public static int g_nRespawnObjectCnt = 0;
        public static int g_nRespawnTryCnt = 0;
        public static int g_nDropRespawn = 0;
        public static int g_nRespawnCnt = 0;
        public static bool g_bIgnoreRandomDamage = true;

        public static float g_fMapLength = 16128.0f;

        public static float s_fTileSize = 0.0f;
        public static int s_nCurrentRegionIdx = 0;

        public static TerrainSeamlessWorldInfo g_SeamlessWorldInfo = new TerrainSeamlessWorldInfo();

        public static DropGroup nullDropGroup = new DropGroup();

        public static Dictionary<int, string> g_hsString = new Dictionary<int, string>();
        public static SummonExpTable[] g_vSummonExpTable = new SummonExpTable[301];
        public static List<ExpTable> g_vExpTable = new List<ExpTable>();
        public static Dictionary<int, PetBase> g_hsPetBase = new Dictionary<int, PetBase>();
        public static Dictionary<int, StateInfo> g_vStateInfo = new Dictionary<int, StateInfo>();
        public static Dictionary<int, JobInfo> g_hsJobInfo = new Dictionary<int, JobInfo>();
        public static Dictionary<int, CreatureStat> g_hsStats = new Dictionary<int, CreatureStat>();
        public static Dictionary<uint, MonsterBase> g_hsMonsters = new Dictionary<uint, MonsterBase>();
        public static Dictionary<int, JobLevelBonus> g_hsJobLevelBonus = new Dictionary<int, JobLevelBonus>();
        public static Dictionary<int, NewJobLevelBonus> g_hsNewJobLevelBonus = new Dictionary<int, NewJobLevelBonus>();
        public static List<string> g_vBanWord = new List<string>();
        public static Dictionary<string, MarketInfo> g_hsMarketInfo = new Dictionary<string, MarketInfo>();
        public static Dictionary<int, SetItemEffectInfo> g_hsSetItemEffectInfo = new Dictionary<int, SetItemEffectInfo>();
        public static List<ScriptRegionInfo> g_vScriptEvent = new List<ScriptRegionInfo>();
        public static List<ScriptRegion> g_vRegionList = new List<ScriptRegion>();
        public static List<MonsterRespawnInfo> g_vMonsterRespawnInfo = new List<MonsterRespawnInfo>();
        public static Dictionary<int, PropContactScriptInfo> g_hsPropScriptInfo = new Dictionary<int, PropContactScriptInfo>();
        public static QuadTreeScanner g_pQuadScanner;
        public static List<RespawnObject> vRegenList = new List<RespawnObject>();
        public static List<NPCBase> g_vNPCInfo = new List<NPCBase>();
        public static List<NPC> g_vNPC = new List<NPC>();
        public static NPCRespawnObject s_NPCRespawnObject = new NPCRespawnObject();
        public static NPC g_pCurrentNPC = null;
        public static X2D.QuadTreeMapInfo g_qtLocationInfo;
        public static X2D.QuadTreeMapInfo g_qtBlockInfo;
        public static X2D.QuadTreeMapInfo g_qtAutoCheckBlockInfo;

        public static List<QuestLink> g_vQuestLink = new List<QuestLink>();
        public static List<RandomPool> g_vRandomPool = new List<RandomPool>();
        public static List<SkillTreeGroup> g_vSkillTree = new List<SkillTreeGroup>();
        public static Dictionary<int, SkillBase> g_hsSkillBase = new Dictionary<int, SkillBase>();
        public static Dictionary<int, DropGroup> g_hsDropGroupInfo = new Dictionary<int, DropGroup>();
        public static Dictionary<int, SummonBase> g_hsSummonInfo = new Dictionary<int, SummonBase>();
        public static Dictionary<int, List<MonsterBase.MonsterItemDropInfo>> g_hsMonsterDropInfo = new Dictionary<int, List<MonsterBase.MonsterItemDropInfo>>();

        public static List<int> g_vSummonPrefix = new List<int>();
        public static List<int> g_vSummonPostFix = new List<int>();

        public static List<AllowedCommandInfo> g_vAllowedCommandsList = new List<AllowedCommandInfo>();

        public static List<WayPointInfo> g_vWayPoint = new List<WayPointInfo>();


// UserDefinedType: GameContent
// Enum           :   <unnamed-tag>, Type: int
// Data           :     constant 0x1, Constant, Type: int, LOCAL_INFO_KOREA
// Data           :     constant 0x2, Constant, Type: int, LOCAL_INFO_HONGKONG
// Data           :     constant 0x4, Constant, Type: int, LOCAL_INFO_AMERICA
// Data           :     constant 0x8, Constant, Type: int, LOCAL_INFO_GERMAN
// Data           :     constant 0x10, Constant, Type: int, LOCAL_INFO_JAPAN
// Data           :     constant 0x20, Constant, Type: int, LOCAL_INFO_TAIWAN
// Data           :     constant 0x40, Constant, Type: int, LOCAL_INFO_CHINA
// Data           :     constant 0x80, Constant, Type: int, LOCAL_INFO_FRANCE
// Data           :     constant 0x100, Constant, Type: int, LOCAL_INFO_RUSSIA
// Data           :     constant 0x200, Constant, Type: int, LOCAL_INFO_MALAYSIA
// Data           :     constant 0x400, Constant, Type: int, LOCAL_INFO_SINGAPORE
// Data           :     constant 0x800, Constant, Type: int, LOCAL_INFO_VIETNAM
// Data           :     constant 0x1000, Constant, Type: int, LOCAL_INFO_THAILAND
// Data           :     constant 0x2000, Constant, Type: int, LOCAL_INFO_MIDEAST
// Data           :     constant 0x4000, Constant, Type: int, LOCAL_INFO_TURKEY
// Data           :     constant 0x20000000, Constant, Type: int, LOCAL_EXCLUDE_TEST_SERV
// Data           :     constant 0x40000000, Constant, Type: int, LOCAL_EXCLUDE_SERVICE_SERV
// Enum           :   <unnamed-tag>, Type: int
// Data           :     constant 0x1, Constant, Type: int, WAY_POINT_CIRCULAR
// Data           :     constant 0x2, Constant, Type: int, WAY_POINT_RETURN
// Function       :   public static void GameContent::SetWayPointSpeed(int, int)
// Function       :   public static void GameContent::SetWayPointType(int, int)
// Function       :   public static void GameContent::AddWayPoint(int, float, float)
// Function       :   public static const struct GameContent::WAY_POINT_INFO * GameContent::GetWayPoint(int)

        public static bool SelectItemIDFromDropGroup(int nDropGroupID, out int nItemID, out long nItemCount)
        {
            nItemID = 0;
            nItemCount = 1;

            DropGroup dg = GameContent.GetDropGroupInfo(nDropGroupID);
            if (dg != null)
            {
                int cp = 0;
                int p = Globals.GetRandomInt32(1, 100000000);
                for(int i = 0; i < DropGroup.MAX_DROP_GROUP;++i)
                {
                    cp += dg.drop_percentage[i];
                    if(p < cp)
                    {
                        nItemID = dg.drop_item_id[i];
                        nItemCount = Globals.GetRandomInt32(dg.drop_min_count[i], dg.drop_max_count[i]);
                        return true;
                    }
                }
            }
            nItemID = 0;
            nItemCount = 1;
            return false;
        }

// Function       :   public static void GameContent::EnumNPCByNPCId(class std::vector<StructNPC *,std::allocator<StructNPC *> > &, int)
        public static JobInfo GetJobInfo(int job_id)
        {
            if (g_hsJobInfo.ContainsKey(job_id))
                return g_hsJobInfo[job_id];
            return null;
        }

        public static CreatureStat GetStatInfo(int stat_id)
        {
            if(g_hsStats.ContainsKey(stat_id))
                return g_hsStats[stat_id];
            return Creature.baseStat;
        }

        public static MonsterBase GetMonsterInfo(uint monster_id)
        {
            if(g_hsMonsters.ContainsKey(monster_id))
                return g_hsMonsters[monster_id];
            return null;
        }

        public static List<MonsterBase.MonsterItemDropInfo> GetMonsterDropTable(int nItemDropInfoID)
        {
            if(g_hsMonsterDropInfo.ContainsKey(nItemDropInfoID))
            {
                return g_hsMonsterDropInfo[nItemDropInfoID];
            }
            return new List<MonsterBase.MonsterItemDropInfo>();
        }

        public static DropGroup GetDropGroupInfo(int drop_group_id)
        {
            if(g_hsDropGroupInfo.ContainsKey(drop_group_id))
                return g_hsDropGroupInfo[drop_group_id];
            return nullDropGroup;
        }

// Function       :   public static struct SummonBase * GameContent::GetSummonInfo(int)
// Function       :   public static bool IsUniqueSummonName(const char *)
// Function       :   public static class std::basic_string<char,std::char_traits<char>,std::allocator<char> > GameContent::GetUniqueName(int)
// Function       :   public static class std::basic_string<char,std::char_traits<char>,std::allocator<char> > GameContent::GetSummonName()
        public static PetBase GetPetInfo(int pet_id)
        {
            if(g_hsPetBase.ContainsKey(pet_id))
                return g_hsPetBase[pet_id];
            return null;
        }

        public static StateInfo GetStateInfo(int state_id)
        {
            if (g_vStateInfo.ContainsKey(state_id))
                return g_vStateInfo[state_id];
            return null;
        }

        public static SkillBase GetSkillBase(int skill_id)
        {
            if(g_hsSkillBase.ContainsKey(skill_id))
                return g_hsSkillBase[skill_id];
            return null;
        }


        public static MarketInfo GetMarketInfo(string name)
        {
            if(g_hsMarketInfo.ContainsKey(name))
                return g_hsMarketInfo[name];
            return null;
        }

        public static long GetNeedExp(int level)
        {
            int l = level;
            if(l < 1)
                l = 1;
            if(l > 300)
                l = 300;
            if(g_vExpTable.Count < l)
                l = g_vExpTable.Count - 1;

            return g_vExpTable[l-1].exp;
        }


        public static long GetNeededSummonExp(int level)
        {
            if((uint)level <= 300)
                return g_vSummonExpTable[level].normal;

            return 0;
        }

        public static int GetNeedJpForJobLevelUp(int level, int job_depth)
        {
            int jd = job_depth;
            if (jd > 3)
                jd = 3;
            if (jd < 0)
                jd = 0;

            return (int)g_vExpTable[level-1].jp[jd];
        }

        public static float GetNeedJpForSkillLevelUp(int skill_id, int skill_level, int nJobId)
        {
// .text:004A1B7A this            = std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > ptr -18h
// .text:004A1B7A it              = std::_Vector_iterator<SkillTree,std::allocator<SkillTree> > ptr -10h
            SkillBase pSkillBase;               // = dword ptr -8
            float jp_ratio;                     // = dword ptr -4
// .text:004A1B7A skill_id        = dword ptr  8
// .text:004A1B7A skill_level     = dword ptr  0Ch
// .text:004A1B7A nJobId          = dword ptr  10h
            List<SkillTree> trees;

// Data           :   ebp Relative, [FFFFFFF0], Local, Type: class std::_Vector_iterator<SkillTree,std::allocator<SkillTree> >, it

            pSkillBase = GameContent.GetSkillBase(skill_id);
            trees = getSkillTree(nJobId);
            jp_ratio = -1.0f;
            if (pSkillBase.uid != 0 && skill_level <= 50 && trees != null)
            {
                foreach (SkillTree st in trees)
                {
                    if(st.skill_id == skill_id && st.max_skill_lv >= skill_level)
                    {
                        jp_ratio = st.jp_ratio;
                    }
                }
                if ( -1.0f == jp_ratio )
                    jp_ratio = 1.0f;
                return (float)pSkillBase.GetNeedJobPoint(skill_level) * jp_ratio;
            }
            return -1;
        }

        public static bool IsValidItemCode(int code)
        {
            return Item.IsValidItemCode(code);
        }
// Function       :   public static bool GameContent::IsBannedWord(const char *)

        public static int IsLearnableSkill(Creature pCreature, int skill_id, int skill_level, out int job_id)
        {
            int ilsResult = 6;

            ilsResult = 6;
            job_id = 0;

            for (int i = 0; i < 4; ++i)
            {
                if (pCreature.GetPrevJobLevel(i) != 0)
                {
                    ilsResult = isLearnableSkill(pCreature, skill_id, skill_level, pCreature.GetPrevJobId(i), pCreature.GetPrevJobLevel(i));

                    if (ilsResult == 0)
                    {
                        //                        if (!job_id)
                        //                            return v4;
                        job_id = pCreature.GetPrevJobId(i);
                        break;
                    }
                    if (ilsResult != 6 && ilsResult != 16 && ilsResult != 14)
                        break;
                }
            }
            if (ilsResult == 6 || ilsResult == 16 || ilsResult == 14)
            {
                ilsResult = isLearnableSkill(pCreature, skill_id, skill_level, pCreature.GetJobId(), pCreature.GetJobLevel());
                if (ilsResult == 0)
                    job_id = pCreature.GetJobId();

//                if ( !v4 && job_id )
//                    job_id = pCreature.GetJobId();
            }
            return ilsResult;
        }

// Function       :   public static bool GameContent::LearnAllSkill(struct StructCreature *)

        public static CreatureStat GetJobLevelBonus(int depth, int[] jobs, int[] levels)
        {
            int i;              // 84   54h
            uint idx;           // 112  70h
            float l;
            float v0;
            float v1;
            float v2;
            float v3;
            float v4;

            CreatureStat res = new CreatureStat();

            i = 0;

            if (depth >= 0)
            {
                for (i = 0; i < 4; ++i)
                {
                    if (g_hsNewJobLevelBonus.ContainsKey(jobs[i]))
                    {
                        NewJobLevelBonus jlb = g_hsNewJobLevelBonus[jobs[i]];
                        res.strength += (int)jlb.Bonuses[levels[i]].strength;
                        res.vital += (int)jlb.Bonuses[levels[i]].vital;
                        res.dexterity += (int)jlb.Bonuses[levels[i]].dexterity;
                        res.agility += (int)jlb.Bonuses[levels[i]].agility;
                        res.intelligence += (int)jlb.Bonuses[levels[i]].intelligence;
                        res.mentality += (int)jlb.Bonuses[levels[i]].mentality;
                        res.luck += (int)jlb.Bonuses[levels[i]].luck;
                    }
                }
            }

//             if (depth >= 0)
//             {
//                 for (i = 0; i < 4; ++i)
//                 {
//                     if (g_hsJobLevelBonus.ContainsKey(jobs[i]))
//                     {
//                         JobLevelBonus jlb = g_hsJobLevelBonus[jobs[i]];
// 
//                         v1 = (levels[i] - 20);
//                         if (levels[i] > 40)
//                             v1 = 20;
//                         // caps the overbreeding
//                         v2 = (levels[i] - 40);
//                         if (levels[i] >= 50)
//                             v2 = 10;
//                         v0 = (float)levels[i];
//                         if (levels[i] > 20)
//                             v0 = 20;
//                         if (v1 <= 0)
//                             v1 = 0;
//                         if (v2 <= 0)
//                             v2 = 0;
// 
//                         res.strength += (int)((v1 * jlb.strength[1]) + (v2 * jlb.strength[2]) + (jlb.strength[3]) + (v0 * jlb.strength[0]));
//                         res.vital += (int)((v1 * jlb.vital[1]) + (v2 * jlb.vital[2]) + (jlb.vital[3]) + (v0 * jlb.vital[0]));
//                         res.dexterity += (int)((v1 * jlb.dexterity[1]) + (v2 * jlb.dexterity[2]) + (jlb.dexterity[3]) + (v0 * jlb.dexterity[0]));
//                         res.agility += (int)((v1 * jlb.agility[1]) + (v2 * jlb.agility[2]) + (jlb.agility[3]) + (v0 * jlb.agility[0]));
//                         res.intelligence += (int)((v1 * jlb.intelligence[1]) + (v2 * jlb.intelligence[2]) + (jlb.intelligence[3]) + (v0 * jlb.intelligence[0]));
//                         res.mentality += (int)((v1 * jlb.mentality[1]) + (v2 * jlb.mentality[2]) + (jlb.mentality[3]) + (v0 * jlb.mentality[0]));
//                         res.luck += (int)((v1 * jlb.luck[1]) + (v2 * jlb.luck[2]) + (jlb.luck[3]) + (v0 * jlb.luck[0]));
//                     }
//                 }
//             }

//             res.strength /= 100;
//             res.vital /= 100;
//             res.dexterity /= 100;
//             res.agility /= 100;
//             res.intelligence /= 100;
//             res.mentality /= 100;
//             res.luck /= 100;
            return res;
        }

// Function       :   public static struct CreatureStat GameContent::GetSummonLevelBonus(int, int, int)
// Function       :   public static bool GameContent::IsAllowedCommand(int, const char *, const char *)
        public static string GetString(int string_id)
        {
            if(g_hsString.ContainsKey(string_id))
                return g_hsString[string_id];
            return "<NULL>";
        }

// Function       :   public static bool GameContent::GetRandomPoolInfo(int, class std::vector<GameContent::RANDOM_POOL_INFO,std::allocator<GameContent::RANDOM_POOL_INFO> > &, int)

        public static bool IsInRandomPoolMonster(int group_id, int monster_id)
        {
            bool result;
//             ArMoveVector::MOVE_INFO *v3; // eax@11
//             ArMoveVector::MOVE_INFO *v4; // eax@14
//             std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > this; // [sp+8h] [bp-18h]@5
//             std::_Vector_iterator<GameContent::RANDOM_POOL_INFO,std::allocator<GameContent::RANDOM_POOL_INFO> > itRandom; // [sp+10h] [bp-10h]@8
//             std::_Vector_iterator<RANDOM_POOL,std::allocator<RANDOM_POOL> > it; // [sp+18h] [bp-8h]@5

            if (group_id == monster_id)
            {
                result = true;
            }
            else
            {
                if (group_id < 0)
                {
/*
                    std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                        &this,
                        dword_64F594,
                        &g_vRandomPool);
                    it.baseclass_0.baseclass_0.baseclass_0._Mycont = this.baseclass_0.baseclass_0._Mycont;
                    it.baseclass_0._Myptr = this._Myptr;
                    while ( 1 )
                    {
                        std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                            &itRandom,
                            dword_64F598,
                            &g_vRandomPool);
                        if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                                 &it,
                                 &itRandom) )
                            break;
                        if ( group_id == LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it)->end.x) )
                        {
                            v3 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it);
                            std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                                &itRandom,
                                LODWORD(v3->end.z),
                                &v3->end.y);
                            while ( 1 )
                            {
                                v4 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it);
                                std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                                    &this,
                                    LODWORD(v4->end.face),
                                    &v4->end.y);
                                if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                                         &itRandom,
                                         &this) )
                                    break;
                                if ( LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&itRandom)->end.x) == monster_id )
                                    return 1;
                                std::_Vector_const_iterator<std::pair<GameContent::HUNTAHOLIC_MONSTER_RESPAWN_INFO_const___unsigned_long>_std::allocator<std::pair<GameContent::HUNTAHOLIC_MONSTER_RESPAWN_INFO_const___unsigned_long>>>::operator__(&itRandom);
                            }
                            break;
                        }
                        std::_Vector_const_iterator<StructCreature::AdditionalDamageInfo_std::allocator<StructCreature::AdditionalDamageInfo>>::operator__(&it);
                    }
*/
                    result = false;
                }
                else
                {
                    result = false;
                }
            }
            return result;
        }
// Function       :   public static const class std::vector<SetItemEffectInfo *,std::allocator<SetItemEffectInfo *> > * GameContent::GetSetItemEffectInfoVector(const int)
// Function       :   public static void Nomalize(float *, float *)

        public static bool IsBlocked(float x, float y)
        {

            if (x < 0 || x > g_nMapWidth || y < 0 || y > g_nMapHeight)
                return true;
            if(GameRule.bIsNoCollisionCheck)
                return false;

            return g_qtBlockInfo != null && g_qtBlockInfo.Collision(new Pointf(x, y));
        }

        public static bool isValidTarget(Player pClient, GameObject pObj)
        {
            return GameContent.IsVisibleRegion((uint)(pClient.mv.x / GameContent.g_nRegionSize),
                (uint)(pClient.mv.y / GameContent.g_nRegionSize),
                (uint)(pObj.mv.x / GameContent.g_nRegionSize),
                (uint)(pObj.mv.y / GameContent.g_nRegionSize)) != 0;
        }

        public static uint IsVisibleRegion(uint rx, uint ry, uint _rx, uint _ry)
        {
            uint result = 0;

            uint cx = _rx - rx + 3;
            uint cy = _ry - ry + 3;
            if (cx <= 6 && cy <= 6)
                result = 1;// ArRegionContainer.s_Matrix[cx + (7 * cy)];
            return result;
        }

// Function       :   public static void GameContent::GetCollisionPolygons(float, float, float, float, class std::vector<X2D::Polygon<int> *,std::allocator<X2D::Polygon<int> *> > &)
// Function       :   public static bool CollisionCheckForAuto(float, float, float, float)

        public static bool CollisionToLine(float x1, float y1, float x2, float y2)
        {
//             bool result; // al@2
//             X2D::Line<int> line; // [sp+0h] [bp-10h]@1
// 
//             line.begin.x = x1;
//             line.begin.y = y1;
//             line.end.x = x2;
//             line.end.y = y2;
            if (GameRule.bIsNoCollisionCheck )
                return false;
            return g_qtBlockInfo.m_MasterNode.LooseCollision(new Linef(new Pointf(x1,y1), new Pointf(x2,y2)));
        }

        public static int GetLocationId(float x, float y)
        {
            int loc_id = 0;
            int priority = 0x7fffffff;
            X2D.Pointf pt = new X2D.Pointf();
            pt.x = x;
            pt.y = y;
            X2D.QuadTreeMapInfo.FunctorAdaptor fn = new X2D.QuadTreeMapInfo.FunctorAdaptor();
            g_qtLocationInfo.Enum(pt, fn);

            foreach (MapLocationInfo info in fn.pResult)
            {
                if(info.priority < priority)
                {
                    loc_id = info.location_id;
                    priority = info.priority;
                }
            }
            return loc_id;
        }
// Function       :   public static void GameContent::LoadScript()
// Function       :   public static void GameContent::ApplyQuestLink()

        public static void ClearQuestLink()
        {
/*
                StructNPC **v0; // eax@2
            std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > this; // [sp+4h] [bp-10h]@1
            std::_Vector_iterator<StructNPC *,std::allocator<StructNPC *> > it; // [sp+Ch] [bp-8h]@1

            std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                &this,
                dword_64F564,
                &g_vNPC);
            it.baseclass_0.baseclass_0.baseclass_0._Mycont = this.baseclass_0.baseclass_0._Mycont;
            it.baseclass_0._Myptr = this._Myptr;
            while ( 1 )
            {
                std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                    &this,
                    dword_64F568,
                    &g_vNPC);
                if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(&it, &this) )
                    break;
                v0 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it);
                StructNPC::ClearQuestLink(*v0);
                std::_Vector_const_iterator<AutoAuctionInfo___std::allocator<AutoAuctionInfo__>>::operator__(&it);
            }
            std::vector<QuestLink_std::allocator<QuestLink>>::clear(&g_vQuestLink);

*/
        }

        public static NPC GetNewNPC(NPCBase npc_info, byte layer)
        {
            NPC npc = new NPC(npc_info);
            npc.m_layer = layer;
            g_vNPC.Add(npc);

            npc.CalculateStat();

            foreach (QuestLink ql in g_vQuestLink)
            {
                if(ql.nNPCId == npc.m_BaseInfo.id)
                {
                    npc.LinkQuest(ql);
                }
            }
            return npc;
        }

        public static void RelinkNPCQuests()
        {
            foreach (NPC npc in g_vNPC)
            {
                npc.ClearQuestLink();
                foreach (QuestLink ql in g_vQuestLink)
                {
                    if (ql.nNPCId == npc.m_BaseInfo.id)
                    {
                        npc.LinkQuest(ql);
                    }
                }
            }

        }

        public static void ReloadQuests()
        {
            g_vQuestLink.Clear();
            DBLoader_Quest ql = new DBLoader_Quest(RappelzServer.arcman);
            ql.onProcess();
            RelinkNPCQuests();

        }

//         public static NPC GetNPCFromQuest(int code, int pos)
//         {
//             foreach (QuestLink ql in g_vQuestLink)
//             {
//                 if (ql.nNPCId == npc.m_BaseInfo.id)
//                 {
//                     npc.LinkQuest(ql);
//                 }
//             }
//             return npc;
//         }

        public static NPCBase GetNPCInfo(int id)
        {
            foreach (NPCBase b in g_vNPCInfo)
            {
                if(b.id == id)
                    return b;
            }
            return null;
        }


        public static void AddNPCToRespawnObject(NPC npc)
        {
            s_NPCRespawnObject.AddNPCRespawn(npc);
        }

        public static void InitNPCRespawnObject()
        {
            s_NPCRespawnObject.Init();
        }

        public static void AddNPCToWorld()
        {
            foreach (NPCBase npc in g_vNPCInfo)
            {
                if (npc.spawn_type == (int) NPCBase.SpawnType.Normal || npc.spawn_type == (int)NPCBase.SpawnType.Cash && (GameRule.bIsCashUsableServer || !GameRule.bIsServiceServer))
                {
                    if (npc.roaming_id != 0)
                    {
//                         v5 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(v4);
//                         v6 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((a1 - 24));
//                         v7 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((a1 - 24));
//                         v8 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((a1 - 24));
//                         v9 = v7[4].end.face;
//                         v10 = v8->end.x;
//                         *(a1 - 16) = 12 * v5->end_time;
//                         *(a1 - 72) = LODWORD(v6->end.face);
//                         v11 = *(a1 - 16);
//                         *(a1 - 84) = 1;
//                         *(a1 - 80) = LODWORD(v10);
//                         *(a1 - 16) = v11;
//                         *(a1 - 76) = LODWORD(v9);
//                         *(a1 - 68) = *(a1 - 16);
//                         v12 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((a1 - 24))[2].end_time;
//                         RoamingManager.Instance.AddRoamingCreatureRespawnInfo(v12, (a1 - 84));
                    }
                    else
                    {
                        int channel_id = ChannelManager.GetChannelId(npc.x, npc.y);
                        List<byte> channels = new List<byte>();
                        ChannelManager.GetLayersOfChannel(channel_id, ref channels);

                        foreach (byte l in channels)
                        {
                            NPC nn = GameContent.GetNewNPC(npc, l);
                            AddNPCToRespawnObject(nn);
                        }
                    }
                }
            }
            InitNPCRespawnObject();
        }

        public static void AddRespawnObjectToWorld()
        {
            foreach (MonsterRespawnInfo ri in g_vMonsterRespawnInfo)
            {
                MonsterRespawnInfo nri = new MonsterRespawnInfo(ri);
                float cx = (nri.right  - nri.left) * 0.5f + nri.left;
                float cy = (nri.top - nri.bottom) * 0.5f + nri.bottom;
                int channel_id = ChannelManager.GetChannelId(cx,cy);
                int dungeon_id = DungeonManager.Instance.GetDungeonID(cx,cy);
                if (channel_id != 0)
                {
                    if (ChannelManager.GetChannelType(channel_id) == 1 )
                    {
                        List<byte> layers = new List<byte>();
                        ChannelManager.GetLayersOfChannel(channel_id, ref layers);

                        foreach (byte b in layers)
                        {
                            nri.layer = b;
                            AddRespawnObject(nri);
                        }
                    }
                    else
                    {
                        if (dungeon_id != 0)
                        {
                            nri.dungeon_id = dungeon_id;
                            AddRespawnObject(nri);
//                            DungeonManager.Instance.RegisterDungeonMonsterRespawnInfo(dungeon_id, nri);
                        }
                    }
                }
                else
                {
                    AddRespawnObject(nri);
                }
            }
        }
// Function       :   public static void GameContent::SetEventDrop(int, const int, const int)

        public static int GetEventDropItemCode()
        {
            return 0;
        }

        public static int GetEventDropItemCount()
        {
            return 0;
        }

        public static uint GetEventDropItemFlag()
        {
            return 0;
        }
// Function       :   public static void GameContent::ClearBannedWord()
        public static void RegisterBannedWord(string name)
        {
            g_vBanWord.Add(name);
        }

        public static void RegisterStateInfo(StateInfo info)
        {
            if(!g_vStateInfo.ContainsKey(info.id))
                g_vStateInfo.Add(info.id, info);
            else
                g_vStateInfo[info.id].Copy(info);
        }

        public static void RegisterSkillTree(SkillTree info)
        {
            List<SkillTree> stl = getSkillTree(info.job_id);

            foreach (SkillTreeGroup stg in g_vSkillTree)
            {
                if (stg.job_id == info.job_id && stg.skill_id == info.skill_id)
                {
                    stg.skillTrees.Add(info);
                    return;
                }
            }
            SkillTreeGroup g = new SkillTreeGroup();
            g.job_id = info.job_id;
            g.skill_id = info.skill_id;
            g.skillTrees.Add(info);
            g_vSkillTree.Add(g);
        }

        public static void RegisterJobInfo(JobInfo info)
        {
            if (g_hsJobInfo.ContainsKey(info.id))
            {
                JobInfo ts = g_hsJobInfo[info.id];
                ts.Copy(info);
            }
            else
            {
                g_hsJobInfo.Add(info.id, info);
            }
        }

        public static void RegisterStatInfo(CreatureStat info)
        {
            if (g_hsStats.ContainsKey(info.stat_id))
            {
                CreatureStat ts = g_hsStats[info.stat_id];
                ts.Copy(info);
            }
            else
            {
                g_hsStats.Add(info.stat_id, info);
            }
        }

        public static void RegisterExpTable(int level, long exp, int jp_0, int jp_1, int jp_2, int jp_3)
        {
            ExpTable tmpTable;

            int count = g_vExpTable.Count;
            if (count < level )
            {
                tmpTable = new ExpTable();
                tmpTable.exp = exp;
                tmpTable.jp[0] = jp_0;
                tmpTable.jp[1] = jp_1;
                tmpTable.jp[2] = jp_2;
                tmpTable.jp[3] = jp_3;
                int cl = level - count;
                do
                {
                    g_vExpTable.Add(tmpTable);
                    --cl;
                }
                while (cl != 0);
            }
            else
            {
                tmpTable = g_vExpTable[level-1];
                tmpTable.exp = exp;
                tmpTable.jp[0] = jp_0;
                tmpTable.jp[1] = jp_1;
                tmpTable.jp[2] = jp_2;
                tmpTable.jp[3] = jp_3;
            }
        }

        public static void RegisterSummonExpTable(int level, long normal_exp, long growth_exp, long evolve_exp)
        {
            SummonExpTable tmpTable;

            if (g_vSummonExpTable[level] == null)
            {
                tmpTable = new SummonExpTable();
                tmpTable.normal = normal_exp;
                tmpTable.growth = growth_exp;
                tmpTable.evolve = evolve_exp;
                g_vSummonExpTable[level] = tmpTable;
            }
            else
            {
                tmpTable = g_vSummonExpTable[level];
                tmpTable.normal = normal_exp;
                tmpTable.growth = growth_exp;
                tmpTable.evolve = evolve_exp;
            }

        }

        public static bool RegisterDropGroupInfo(DropGroup info)
        {
            if(!g_hsDropGroupInfo.ContainsKey(info.uid))
            {
                g_hsDropGroupInfo.Add(info.uid, info);
            }
            else 
            {
                g_hsDropGroupInfo[info.uid] = info;
            }
            return true;
        }

        public static void RegisterMonsterDropTable(int nID, List<MonsterBase.MonsterItemDropInfo> vMonsterItemDropInfo)
        {
            if(!g_hsMonsterDropInfo.ContainsKey(nID))
            {
                g_hsMonsterDropInfo.Add(nID, new List<MonsterBase.MonsterItemDropInfo>());
            }

            foreach (MonsterBase.MonsterItemDropInfo drop in vMonsterItemDropInfo)
            {
                g_hsMonsterDropInfo[nID].Add(drop);
            }

        }


        public static bool RegisterMonsterInfo(MonsterBase info)
        {
            if(!g_hsMonsters.ContainsKey((uint)info.uid))
                g_hsMonsters.Add((uint)info.uid, info);

            
            return true;
        }

        public static bool RegisterQuestLink(QuestLink ql)
        {
            g_vQuestLink.Add(ql);
            return true;
        }

        public static QuestLink GetQuestLink(int code, int start_id)
        {
            foreach (QuestLink l in g_vQuestLink)
            {
                if (l.code == code && (l.nStartTextId == start_id || start_id == 0))
                    return l;
            }
            return null;
        }

        public static bool RegisterSummonInfo(SummonBase info)
        {
//             SummonBase *v1; // eax@2
//             SummonLevelBonus bonus; // [sp+8h] [bp-40h]@3
//             unsigned int idx; // [sp+44h] [bp-4h]@1

            if(!g_hsSummonInfo.ContainsKey(info.uid))
            {
                g_hsSummonInfo.Add(info.uid,info);
            }
//             idx = 0;
//             if ( KHash<std::vector<AuctionInfo___std::allocator<AuctionInfo__>>___khash_def::hashPr_mod_basic<int>>::lookup(
//                      &summon_code_inst,
//                      &info->uid,
//                      &idx) )
//             {
//                 v1 = std::vector<SummonBase_std::allocator<SummonBase>>::operator__(&g_vSummonInfo, idx);
//                 SummonBase::operator_(v1, info);
//             }
//             else
//             {
//                 SummonLevelBonus SummonLevelBonus(&bonus);
//                 std::vector<SummonBase_std::allocator<SummonBase>>::push_back(&g_vSummonInfo, info);
//                 std::vector<SummonLevelBonus_std::allocator<SummonLevelBonus>>::push_back(&g_vSummonLevelBonusInfo, &bonus);
//                 idx = std::vector<SummonBase_std::allocator<SummonBase>>::size(&g_vSummonInfo) - 1;
//                 KHash<std::vector<ItemKeepingInfo___std::allocator<ItemKeepingInfo__>>___khash_def::hashPr_mod_basic<int>>::_add(
//                     &summon_code_inst,
//                     info->uid % summon_code_inst.m_nCapacity,
//                     &info->uid,
//                     &idx);
//             }
            return true;

        }

        public static bool RegisterPetInfo(PetBase info)
        {
            if(g_hsPetBase.ContainsKey(info.uid))
                return false;

            g_hsPetBase.Add(info.uid, info);
            return true;
        }

        public static bool RegisterSkillBase(SkillBase info)
        {
            if(!g_hsSkillBase.ContainsKey(info.uid))
                g_hsSkillBase.Add(info.uid, info);

            return true;
        }
        
// Function       :   public static bool GameContent::RegisterSkillJobPointTable(int, int *)
        public static bool RegisterStringInfo(int string_id, string szString)
        {
            if (string_id != 0)
            {
                if(!g_hsString.ContainsKey(string_id))
                    g_hsString.Add(string_id, szString);
            }
            return true;
        }

        public static bool RegisterPropContactScriptInfo(int prop_id, int prop_type, int model_info, float x, float y, List<PropContactScriptInfo.FunctionList> vFunctionList)
        {
            if(g_hsPropScriptInfo.ContainsKey(prop_id))
            {
                Globals.Log.Error("Duplicate PropId! - {0}", prop_id);
                return false;
            }

            PropContactScriptInfo pcsi = new PropContactScriptInfo();
            pcsi.prop_type = prop_type;
            pcsi.prop_id = prop_id;
            pcsi.model_info = model_info;
            pcsi.x = x;
            pcsi.y = y;

            foreach(PropContactScriptInfo.FunctionList fl in vFunctionList)
            {
                PropContactScriptInfo.FunctionList fl2 = new PropContactScriptInfo.FunctionList();
                fl2.trigger_id = fl.trigger_id;
                fl2.stdFunction = fl.stdFunction;
                pcsi.vFunctionList.Add(fl2);
            }

            g_hsPropScriptInfo.Add(prop_id, pcsi);
            return true;
        }

        public static void RegisterJobLevelBonusInfo(JobLevelBonus bonus)
        {
            if (g_hsJobLevelBonus.ContainsKey(bonus.job_id))
            {
                JobLevelBonus ts = g_hsJobLevelBonus[bonus.job_id];
                ts.Copy(bonus);
            }
            else
            {
                g_hsJobLevelBonus.Add(bonus.job_id, bonus);
            }
        }

        public static void RegisterJobLevelBonusInfo(int level, int id, NewJobLevelBonus.Bonus bonus)
        {
            if (g_hsNewJobLevelBonus.ContainsKey(id))
            {
                NewJobLevelBonus ts = g_hsNewJobLevelBonus[id];
                ts.Bonuses[level] = bonus;
            }
            else
            {
                NewJobLevelBonus nb = new NewJobLevelBonus();
                nb.Bonuses[level] = bonus;
                g_hsNewJobLevelBonus.Add(id, nb);
            }
        }

// Function       :   public static void GameContent::RegisterSummonLevelBonusInfo(const struct SummonLevelBonus &)
// Function       :   public static void GameContent::RegisterBlockInfo(const struct X2D::Polygon<int> &)
// Function       :   public static void GameContent::RegisterAutoCheckBlockInfo(const struct X2D::Polygon<int> &)

        public static void RegisterMapLocationInfo(MapLocationInfo location_info)
        {
            if(g_qtLocationInfo == null)
            {
                g_qtLocationInfo = new X2D.QuadTreeMapInfo(GameContent.g_nMapWidth,GameContent.g_nMapHeight);
            }
            g_qtLocationInfo.Add(location_info);
        }
// Function       :   public static void GameContent::RegisterSummonDefaultName(int, bool)
// Function       :   public static void GameContent::RegisterSummonUniqueName(int, int)

        public static void RegisterRandomPoolInfo(int group_id, int quest_target_id, int target_level)
        {
            RandomPoolInfo rpi = new RandomPoolInfo();
            rpi.level = target_level;
            rpi.quest_target_id = quest_target_id;

            foreach (RandomPool rp in g_vRandomPool)
            {
                if(rp.group_id == group_id)
                {
                    rp.vInfo.Add(rpi);
                    return;
                }
            }

            RandomPool nrp = new RandomPool();
            nrp.group_id = group_id;
            nrp.vInfo.Add(rpi);
            g_vRandomPool.Add(nrp);
        }

        public static void RegisterNPCInfo(NPCBase npc_info)
        {
            g_vNPCInfo.Add(npc_info);
        }

        public static void AddMarketInfo(string szMarketName, int index, int code, long price, int huntaholic_point)
        {
            MarketInfo info = GameContent.GetMarketInfo(szMarketName);
            if (info == null)
            {
                info = new MarketInfo();
                info.szMarketName = szMarketName;
                g_hsMarketInfo.Add(szMarketName, info);
            }

            MarketInfo.MarketTag tag = new MarketInfo.MarketTag();
            tag.index = index;
            tag.code = code;
            tag.price = price;
            tag.huntaholic_point = huntaholic_point;
            info.vItemList.Add(tag);
        }
// Function       :   public static struct NPCBase & GameContent::GetNPCInfo(const int)

        public static void RegisterMonsterRespawnInfo(MonsterRespawnInfo info)
        {
            if (g_hsMonsters.ContainsKey(info.monster_id))
                g_vMonsterRespawnInfo.Add(info);
            else
                Globals.Log.Error("Unable to spawn monster: {0}", info.monster_id);
        }
// Function       :   public static void GameContent::RegisterRaidMonsterRespawnInfo(const struct GameContent::MONSTER_RESPAWN_INFO &)

        public static void RegisterSetItemEffectInfo(SetItemEffectInfo info)
        {
            if(g_hsSetItemEffectInfo.ContainsKey(info.nSetID))
            {
                g_hsSetItemEffectInfo[info.nSetID].Copy(info);
            }
            else
            {
                g_hsSetItemEffectInfo.Add(info.nSetID, info);
            }
        }
// Function       :   public static void GameContent::ClearAllowedCommandsList()

        public static void RegisterAllowedCommandInfo(int nPermission, string pszCommand, string pszParameter)
        {
            lock(g_vAllowedCommandsList)
            {
                if ((nPermission) <= 99)
                {
                    AllowedCommandInfo.CommandInfo ci = new AllowedCommandInfo.CommandInfo();
                    ci.szCommand = pszCommand;
                    ci.szParameter = pszParameter;

                    foreach (AllowedCommandInfo info in g_vAllowedCommandsList)
                    {
                        if (info.nPermisson == nPermission)
                        {
                            info.vCommandInfoList.Add(ci);
                            return;
                        }
                    }

                    AllowedCommandInfo aci = new AllowedCommandInfo();
                    aci.nPermisson = nPermission;
                    aci.vCommandInfoList.Add(ci);
                    g_vAllowedCommandsList.Add(aci);
                }
            }
        }

        public static void AddRespawnObject(MonsterRespawnInfo info)
        {
            if (info != null && info.monster_id != 0)
            {
                RespawnObject ro = new RespawnObject(info);
                ro.m_layer = info.layer;
                List<RespawnObject> list = GetRespawnList();
                list.Add(ro);
                RappelzServer.Instance.SetObjectPriority(ro, SchedulerObject.Priority.Normal);
            }
        }

        public static List<RespawnObject> GetRespawnList()
        {
            return vRegenList;
        }

        public static void AddMonsterToWorld(Monster mob)
        {
            mob.quadTreeItem.Set(mob);
            mob.quadTreeItem.AddMe();
            mob.m_RespawnX = mob.mv.x;
            mob.m_RespawnY = mob.mv.y;

            RappelzServer.Instance.AddObject(mob);
            Globals.Log.Trace("Added Mob (Layer {0} x: {1} y: {2}): {3} ", mob.m_layer, mob.region_x, mob.region_y, mob.GetName());
            mob.m_StatusFlag &= ~Creature.StatusFlags.FirstEnter;
        }

        public static void AddSummonToWorld(Summon pSummon)
        {
            pSummon.quadTreeItem.Set(pSummon);
            pSummon.quadTreeItem.AddMe();

            pSummon.m_StatusFlag |= Creature.StatusFlags.FirstEnter;

            RappelzServer.Instance.AddObject(pSummon);
            pSummon.m_bIsSummoned = true;
            pSummon.m_StatusFlag &= ~Creature.StatusFlags.FirstEnter;

            RappelzServer.Instance.SetObjectPriority(pSummon, SchedulerObject.Priority.Normal);
        }


        public static void RemoveMonsterFromWorld(Monster mob)
        {
            if (mob.m_nHP != 0)
                mob.quadTreeItem.RemoveMe();
            mob.onRemoveFromWorld();

            RappelzServer.Instance.RemoveObject(mob);
        }

        public static void AddNPCToWorld(NPC npc)
        {
            RappelzServer.Instance.AddObject(npc);
            g_pCurrentNPC = npc;
        }

        public static void ClearTamer(Monster pMonster, bool bBroadcastMsg)
        {

            uint tamer = pMonster.GetTamer();
            if (tamer != 0)
            {
                if (bBroadcastMsg)
                    Messages.BroadcastTamingMessage(null, pMonster, 1);

                Player p = Player.get(tamer) as Player;
                if (p != null)
                {
                    p.m_hTamingTarget = 0;
                    while (true)
                    {
                        Item card = p.FindTamingSummonCard(pMonster.GetTameItemCode());
                        if (card == null)
                            break;
                        card.m_Instance.Flag &= ~(uint)ItemInstance.FlagBits.Summon;
                    }
                }
                pMonster.SetTamer(0, 0);
            }
        }

        public static int ShowQuestMenu(Player pPlayer)
        {
            string szBuf;
            string szButtonName;

            ShowQuestMenuNPCQuestFunctor _foStart = new ShowQuestMenuNPCQuestFunctor(0);
            ShowQuestMenuNPCQuestFunctor _foProgress = new ShowQuestMenuNPCQuestFunctor(1);
            ShowQuestMenuNPCQuestFunctor _foEnd = new ShowQuestMenuNPCQuestFunctor(2);

            NPC npc = GameObject.raw_get(pPlayer.GetLastContactLong("npc")) as NPC;
            if (npc != null)
            {
                npc.DoEachStartableQuest(pPlayer, _foStart);
                npc.DoEachInProgressQuest(pPlayer, _foProgress);
                npc.DoEachFinishableQuest(pPlayer, _foEnd);

//                 if ( !_foProgress.vRandomQuestCode._Myfirst
//                   || !(_foProgress.vRandomQuestCode._Mylast - _foProgress.vRandomQuestCode._Myfirst) )
//                 {
//                     if ( !_foEnd.vRandomQuestCode._Myfirst
//                       || !(_foEnd.vRandomQuestCode._Mylast - _foEnd.vRandomQuestCode._Myfirst) )
//                     {
//                         std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                             &rQuestBase,
//                             _foStart.vRandomQuestCode._Myfirst,
//                             &_foStart.vRandomQuestCode.baseclass_0.___u0.baseclass_0);
//                         std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                             &this,
//                             _foStart.vRandomQuestCode._Mylast,
//                             &_foStart.vRandomQuestCode.baseclass_0.___u0.baseclass_0);
//                         if ( !std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
//                                   &rQuestBase,
//                                   &this) )
//                         {
//                             do
//                             {
//                                 szButtonName[27] = LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&rQuestBase)->end.x);
//                                 if ( StructQuest::GetQuestBase(szButtonName[27])->baseclass_0.nLimitLevel > 0 )
//                                     v4 = LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&rQuestBase)->end.x);
//                                 std::_Vector_const_iterator<AutoAuctionInfo___std::allocator<AutoAuctionInfo__>>::operator__(&rQuestBase);
//                                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                                     &this,
//                                     _foStart.vRandomQuestCode._Mylast,
//                                     &_foStart.vRandomQuestCode.baseclass_0.___u0.baseclass_0);
//                             }
//                             while ( !std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
//                                          &rQuestBase,
//                                          &this) );
//                             if ( v4 )
//                             {
//                                 QuestBaseServer qbs = Quest.GetQuestBase(v4);
//                                 szButtonName[26] = v4;
//                                 v12 = v5;
//                                 sprintf(szBuf, "quest_info( %d )");
//                                 szButtonName[23] = 0;
//                                 szButtonName[22] = v12->baseclass_0.nQuestTextId;
//                                 sprintf(szButtonName, "QUEST|%d|%d");
//                                 pPlayer.AddDialogMenu(szButtonName, szBuf);
//                             }
//                         }
//                     }
//                 }
            }
            return 0;
        }


        public static void addChaos(Creature pCorpse, Player pPlayer, float chaos)
        {
            if (pPlayer.m_nMaxChaos > pPlayer.m_nChaos)
            {
                uint ct = Globals.GetArTime();

                ArPosition playerPos = pPlayer.GetCurrentPosition(ct);
                ArPosition corpsePos = pCorpse.GetCurrentPosition(ct);
                if (corpsePos.GetDistance(playerPos) <= 500.0f)
                {
                    int nChaos = GameRule.GetIntValueByRandomInt(chaos);
                    byte nBonusType = 0;
                    byte nBonusPercent = 0;
                    int nBonus = 0;

                    uint cpt = pPlayer.GetContinuousPlayTime();
                    if (pPlayer.IsGameTimeLimited() && cpt >= GameRule.nMaxHealthyGameTime)
                    {
                        chaos *= GameRule.GetGameTimeLimitPenalty(cpt) ;
                    }
                    else 
                    {
                        switch (pPlayer.GetPCBangMode())
                        {
                            case 0:
                                break;

                            case 1:
                                nBonusType = 1;
                                nBonus = (int)((float)nChaos * GameRule.fAllyPCBangChaosBonusRate);
                                nBonusPercent = (byte)(GameRule.fAllyPCBangChaosBonusRate * 100.0f);
                                break;

                            case 2:
                                nBonusType = 2;
                                nBonus = (int)((float)nChaos * GameRule.fPremiumPCBangChaosBonusRate);
                                nBonusPercent = (byte)(GameRule.fPremiumPCBangChaosBonusRate * 100.0f);
                                break;
                        }
                        if (nBonus == 0)
                            nBonusType = 0;
                        nChaos += nBonus;
                    }

                    if (chaos > 0.0f)
                    {
                        PacketOut packet = new PacketOut((ushort)ClientOutPackets.GetChaos);
                        packet.WriteUInt32(pPlayer.m_hHandle);
                        packet.WriteUInt32(pCorpse.m_hHandle);
                        packet.WriteInt32(nChaos);
                        packet.WriteByte(nBonusType);
                        packet.WriteByte(nBonusPercent);
                        packet.WriteInt32(nBonus);

                        RappelzServer.Instance.Broadcast((uint)(pCorpse.mv.x / GameContent.g_nRegionSize), (uint)(pCorpse.mv.y / GameContent.g_nRegionSize), pCorpse.m_layer, packet);
                        pPlayer.AddChaos(nChaos);
                        ServerLog.Log((ushort)0x96C,pPlayer.GetAccountID(),pPlayer.GetSID(),0,0,nChaos,pPlayer.m_nChaos,0,0,0,0,0,pPlayer.GetAccountName(),pPlayer.GetName(),"","");
                    }
                }
            }
        }

        public static void addChaos(Creature pCorpse, int nPartyID, float chaos)
        {
//             int v3; // ebp@0
//             unsigned int v4; // eax@1
//             ArPosition *v5; // eax@1
//             int v6; // ST30_4@1
//             PartyManager *v7; // eax@1
//             int v8; // eax@2
//             double v9; // st7@4
//             double v10; // st6@4
//             unsigned int *v11; // ST30_4@6
//             StructPlayer **v12; // eax@7
// 
//             ::::myPartyFunctor1::myPartyFunctor1((v3 - 76));
//             *(v3 - 4) = 0;
//             v4 = GetArTime();
//             v5 = ArObject::GetCurrentPosition(*(v3 + 8), (v3 - 36), v4);
//             *(v3 - 72) = LODWORD(v5->x);
//             *(v3 - 72 + 4) = LODWORD(v5->y);
//             *(v3 - 72 + 8) = LODWORD(v5->z);
//             v6 = *(v3 + 12);
//             *(v3 - 72 + 12) = LODWORD(v5->face);
//             v7 = PartyManager::GetInstance();
//             PartyManager::DoEachMember(v7, v6, (v3 - 76));
//             if ( *(v3 - 48) )
//                 v8 = (*(v3 - 44) - *(v3 - 48)) >> 2;
//             else
//                 v8 = 0;
//             v9 = *(v3 + 16);
//             *(v3 + 16) = v8;
//             v10 = *(v3 + 16);
//             if ( v8 < 0 )
//                 v10 = v10 + 4294967300.0;
//             v11 = *(v3 - 48);
//             *(v3 + 16) = v9 / v10;
//             std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                 (v3 - 28),
//                 v11,
//                 (v3 - 52));
//             *(v3 - 20) = *(v3 - 28);
//             *(v3 - 16) = *(v3 - 24);
//             while ( 1 )
//             {
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     (v3 - 28),
//                     *(v3 - 44),
//                     (v3 - 52));
//                 if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
//                          (v3 - 20),
//                          (v3 - 28)) )
//                     break;
//                 v12 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((v3 - 20));
//                 addChaos(*(v3 + 8), *v12, *(v3 + 16));
//                 std::_Vector_const_iterator<AutoAuctionInfo___std::allocator<AutoAuctionInfo__>>::operator__((v3 - 20));
//             }
//             std::vector<GameContent::REGEN_INFO_std::allocator<GameContent::REGEN_INFO>>::_Tidy((v3 - 52));
        }


        public static void addEXP(Creature pCorpse, Player pPlayer, float exp, float jp)
        {
            float fJP;
            float fIPDec;
            bool bIsNeedToSendStatus;

            if (pPlayer.m_nHP != 0)
            {
                fJP = jp;
                // remove some immorality points here
                if (pPlayer.m_fImmoralPoint > 0.0f)
                {
                    if ( pCorpse.GetLevel() >= pPlayer.GetLevel())
                    {
                        fIPDec = -1.0f;
                        if (pPlayer.m_fImmoralPoint > GameRule.fCrimeLimit)
                            fIPDec = -0.5f;
                        if (pPlayer.m_nPartyId != 0)
                        {
                            fIPDec = 2.0f / (float)(PartyManager.Instance.GetMemberCount(pPlayer.m_nPartyId) + 1) * fIPDec;
                        }
                        bIsNeedToSendStatus = false;
                        if (pPlayer.m_fImmoralPoint > GameRule.fCrimeLimit && pPlayer.m_fImmoralPoint + fIPDec < GameRule.fCrimeLimit
                          || pPlayer.m_fImmoralPoint > GameRule.fMoralLimit && pPlayer.m_fImmoralPoint + fIPDec < GameRule.fMoralLimit)
                            bIsNeedToSendStatus = true;

                        pPlayer.SetImmoralPoint(pPlayer.m_fImmoralPoint + fIPDec);
                        if ( bIsNeedToSendStatus )
                            Messages.BroadcastStatusMessage(pPlayer);
                    }
                }

                int levelDiff = pPlayer.GetLevel() - pCorpse.GetLevel();
                if (levelDiff > 0)
                {
                    exp = (1.0f - (float)levelDiff * 0.05f) * exp;
                    fJP = (1.0f - (float)levelDiff * 0.05f) * jp;
                }
                uint ct = Globals.GetArTime();
                ArPosition posPlayer = pPlayer.GetCurrentPosition(ct);
                ArPosition posCorpse = pCorpse.GetCurrentPosition(ct);
                if (posCorpse.GetDistance(posPlayer) <= 500.0f)
                {
                    if (exp < 1.0f)
                        exp = 1.0f;
                    if (fJP < 0.0f)
                        fJP = 0.0f;

                    Monster mob = pCorpse as Monster;
                    if (pCorpse.IsMonster() && mob.m_hTamer == pPlayer.m_hHandle)
                    {
                        if (mob.m_bTamedSuccess)
                        {
                            exp = mob.m_pContentInfo.taming_exp_adjust * exp;
                            fJP = mob.m_pContentInfo.taming_exp_adjust * fJP;
                        }
                    }

                    pPlayer.AddExp(GameRule.GetIntValueByRandomInt64(GameRule.fEXPRate * exp),GameRule.GetIntValueByRandomInt(GameRule.fEXPRate * fJP),true);
                }
            }
        }

        public static void addEXP(Creature pCorpse, int nPartyID, int exp, int jp)
        {
            float fLevelPenalty;
            addEXPPartyFunctor1 fn1 = new addEXPPartyFunctor1();
            addEXPPartyFunctor2 fn2 = new addEXPPartyFunctor2();

            uint ct = Globals.GetArTime();
            fn1.pos = pCorpse.GetCurrentPosition(ct);
            fn1.layer = pCorpse.m_layer;

            PartyManager.Instance.DoEachMember(nPartyID, fn1);
            if (fn1.nCount >= 1 )
            {
                if (fn1.nCount < 2)
                {
                    addEXP(pCorpse, fn1.pOneManPlayer, exp, jp);
                    return;
                }

                int levelDiff = fn1.nMaxLevel - fn1.nMinLevel;
                if (levelDiff < fn1.nTotalCount + 40)
                {
                    if (levelDiff >= fn1.nTotalCount + 5)
                    {
                        fLevelPenalty = levelDiff - fn1.nCount - 5;
                        fLevelPenalty = 1.0f - (float) Math.Pow(fLevelPenalty, 1.1) * 0.02f;
                        exp = (int)((float)exp * fLevelPenalty);
                        jp = (int)((float)jp * fLevelPenalty);
                    }
                }
                else 
                {
                    exp = 0;
                    jp = 0;
                }
                // this gets run no matter what
                fn2.nMaxLevel = fn1.nMaxLevel;
                fn2.nTotalLevel = fn1.nTotalLevel;
                fLevelPenalty = 2 * fn1.nCount * fn1.nCount;
                float lp = fLevelPenalty * 0.01f + 1.0f;
                fn2.nSharedEXP = (int)((float)exp * lp);
                fn2.nSharedJP = (int)((float)jp * lp);
                fn2.pCorpse = pCorpse;
                PartyManager.Instance.DoEachMember(nPartyID, fn2);
            }
        }


        public static long GetNeedSummonExp(int level)
        {
            if ((uint)level <= 300)
                return g_vSummonExpTable[level].normal;
            return 0;
        }


        public static bool ProcTame(Monster pMonster)
        {
            long nItemEnhanceAndLevel;              // -120 -78h
            long nItemUID;                          // -80  -50h
            float fTameProbability;                 // -72  -48h
            long nItemCount;                        // -56  -38h
            // it                                   // -48  -30h
            Skill pSkill;                           // -40  -28h
            int nTameItemCode;                      // -32  -20h
            int nItemCode;                          // -24  -18h
            Item pItem;                             // -20  -14h
            bool bDecreaseCount;                    // -14  -0Eh
            bool bCardProtected;                    // -13  -0Dh
            //  .text:0041FE3D pMonster        = dword ptr  8
            Player player;

            if (pMonster.GetTamer() == 0)
                return false;
            player = Player.get(pMonster.GetTamer()) as Player;

            if (player == null || player.m_nHP == 0)
            {
                Messages.BroadcastTamingMessage(null, pMonster, 3);
                return false;
            }

            nTameItemCode = pMonster.GetTameItemCode();
            if (pMonster.mv.GetDistance(player.mv) > 500.0f || nTameItemCode == 0)
            {
                ClearTamer(pMonster, false);
                Messages.BroadcastTamingMessage(player, pMonster, 3);
                return false;
            }
            pItem = player.FindTamingSummonCard(nTameItemCode);

            if (pItem == null)
            {
                Globals.Log.Info("ProcTame: A summon card used for taming is lost. [{0}:{1}]\n", player.GetAccountName(), player.GetName());
                ClearTamer(pMonster, false);
                Messages.BroadcastTamingMessage(player, pMonster, 3);
                return false;
            }

            nItemCode = 20;
            nItemCode -= pMonster.GetLevel();

            // this code is the level-based penalty, we don't want it really
            float lPenalty = 0.05f * (float)((20 - pMonster.GetLevel()) + player.GetLevel());
            if (lPenalty < 0)
            {
                lPenalty = 0;
            }
            else if(lPenalty > 1)
            {
                lPenalty = 1;
            }
            lPenalty = 1; // comment this out to add it back in

            fTameProbability = pMonster.GetTamePercetage() * lPenalty;
            pSkill = player.GetSkill(4003);

            if (pSkill == null)
            {
                // we don't really have this skill, should never get here...
                ClearTamer(pMonster, false);
                nTameItemCode = 3;
                Messages.BroadcastTamingMessage(player, pMonster, nTameItemCode);
                return false;
            }
            bCardProtected = false;

            // see if we have a T-Protect and if so handle it
            Item tProtect = player.FindItemByCode(960019);

            if (tProtect != null && tProtect.IsInInventory()
              && tProtect.m_Instance.OwnerHandle == player.m_hHandle
              && tProtect.m_Instance.nCount > 0)
            {
                player.EraseItem(tProtect, 1);
                bCardProtected = true;
//                   v22 = tProtect.m_Instance.nLevel,
//                   *(v1 - 80) = LODWORD(tProtect.m_Instance.UID),
//                   *(v1 - 76) = HIDWORD(tProtect.m_Instance.UID),
//                   v23 = tProtect.m_Instance.nLevel + 100 * tProtect.m_Instance.nEnhance,
//                   *(v1 - 120) = tProtect.m_Instance.nLevel + 100 * tProtect.m_Instance.nEnhance,
//                   *(v1 - 24) = tProtect.m_Instance.Code,
//                   *(v1 - 52) = HIDWORD(tProtect.m_Instance.nCount),
//                   LODWORD(v23) = tProtect.m_pItemBase,
//                   *(v1 - 116) = tProtect.m_Instance.nLevel + 100 * tProtect.m_Instance.nEnhance,
//                   v24 = *(v23 + 8) == 6,
//                   *(v1 - 56) = v21,
//                   *(v1 - 14) = !v24,
//                   *(v1 - 64) = 1,
//                   *(v1 - 60) = 0,
// 
//                 v24 = *(v1 - 14) == 0;
//                 v25 = *(v1 - 56);
//                 if ( v24 )
//                 {
//                     *(v1 - 64) = tProtect.m_Instance.nCount;
//                 }
//                 else
//                 {
//                     *(v1 - 64) = tProtect.m_Instance.nCount - 1;
//                 }
//                 ServerLog.Log((ushort)0x966,player.GetAccountID(),player.GetSID(),
//                     tProtect.m_Instance.nLevel + 100 * tProtect.m_Instance.nEnhance,tProtect.m_Instance.Code,1,(v1 - 64),
//                     0,0,0,0,tProtect.m_Instance.UID,player.GetAccountName(),player.GetName(),"","");
                Messages.SendChatMessage(false, 32, "@SYSTEM", player, "@243", 0);
            }

            fTameProbability *= (((pSkill.m_SkillBase.m_var[1] * pSkill.m_nEnhance) + (pSkill.m_SkillBase.m_var[0] * pMonster.m_nTamingSkillLevel) + 1) * 1000000);
            if (fTameProbability < Globals.GetRandomInt32(1, 1000000) && player.m_nPermission == 0)
            {
                ServerLog.Log((ushort)0x903,player.GetAccountID(),player.GetSID(),0,nTameItemCode,pMonster.GetTameCode(),0,0,
                    0,(long)player.mv.x, (long)player.mv.y,pItem.m_Instance.UID,player.GetAccountName(),player.GetName(),"","FAIL");
                if (!bCardProtected)
                {
                    player.EraseItem(pItem, 1);
                }
                ClearTamer(pMonster, false);
                nTameItemCode = 3;
                Messages.BroadcastTamingMessage(player, pMonster, nTameItemCode);
                return false;
            }

            ServerLog.Log((ushort)0x903,player.GetAccountID(),player.GetSID(),0,nTameItemCode,pMonster.GetTameCode(),0,0,
                0,(long)player.mv.x, (long)player.mv.y,pItem.m_Instance.UID,player.GetAccountName(),player.GetName(),"","SUCS");

            pItem.m_Instance.Flag = (pItem.m_Instance.Flag & 0xDFFFFFFF) | 0x80000000;
            pItem.DBQuery(new DB_UpdateItem(pItem));
            Messages.SendItemMessage(player, pItem);
            Messages.BroadcastTamingMessage(player, pMonster, 2);
            ClearTamer(pMonster, false);
            return true;
        }


        public static void WarpBegin(Player player)
        {
            if (player.IsUsingSkill() )
                player.CancelSkill();

            if (player.m_hTradeTarget != 0)
            {
                Player tp = Player.get(player.m_hTradeTarget) as Player;
                if (tp != null)
                    tp.CancelTrade(true);
                player.CancelTrade(true);
            }
            if (player.bIsInWorld)
                GameContent.RemovePlayerFromWorld(player);
            if (player.m_pMainSummon != null)
                GameContent.warpBeginSummon(player, player.m_pMainSummon);
            if (player.m_pSubSummon != null)
                GameContent.warpBeginSummon(player, player.m_pSubSummon);
            Pet pet = player.m_pSummonedPet;
            if (pet != null && pet.m_bIsSummoned && pet.bIsInWorld)
            {
                if (pet.IsUsingSkill())
                    pet.CancelSkill();
                GameContent.RemovePetFromWorld(pet);
            }
        }

        public static void RemoveNPCFromWorld(NPC pMob)
        {
            pMob.onRemoveFromWorld();
            RappelzServer.Instance.RemoveObject(pMob);
        }

        public static void RemovePlayerFromWorld(Player pMob)
        {
            pMob.onRemoveFromWorld();
            RappelzServer.Instance.RemoveObject(pMob);
        }

        public static void RemovePetFromWorld(Pet pPet)
        {
            RappelzServer.Instance.SetObjectPriority(pPet, SchedulerObject.Priority.Idle);
            pPet.quadTreeItem.RemoveMe();
            pPet.onRemoveFromWorld();
            RappelzServer.Instance.RemoveObject(pPet);
        }

        public static void RemoveSummonFromWorld(Summon pPet)
        {
            RappelzServer.Instance.SetObjectPriority(pPet, SchedulerObject.Priority.Idle);
            pPet.quadTreeItem.RemoveMe();
            pPet.onRemoveFromWorld();
            RappelzServer.Instance.RemoveObject(pPet);
        }

        public static void warpBeginSummon(Player pPlayer, Summon pSummon)
        {
            if (pSummon != null && pSummon.bIsInWorld)
            {
                if (pSummon.IsUsingSkill())
                    pSummon.CancelSkill();
                RemoveSummonFromWorld(pSummon);
            }
        }

        public static void WarpEnd(Player pPlayer, ArPosition pPosition, byte layer)
        {
// .text:0042069E var_8C          = dword ptr -8Ch
// .text:0042069E var_88          = dword ptr -88h
// .text:0042069E var_84          = dword ptr -84h
// .text:0042069E var_80          = dword ptr -80h
// .text:0042069E pos             = ArPosition ptr -70h
// .text:0042069E result          = ArPosition ptr -60h
// .text:0042069E n2              = qword ptr -50h
// .text:0042069E n3              = qword ptr -48h
// .text:0042069E n4              = qword ptr -40h
// .text:0042069E n5              = qword ptr -38h
// .text:0042069E n6              = qword ptr -30h
// .text:0042069E n7              = qword ptr -28h
// .text:0042069E n8              = qword ptr -20h
// .text:0042069E n9              = qword ptr -18h
// .text:0042069E n11             = qword ptr -10h
// .text:0042069E pSummon         = qword ptr -8
// .text:0042069E nChannelID      = dword ptr  8
// .text:0042069E pPosition       = dword ptr  0Ch
// .text:0042069E layer           = dword ptr  10h
// 
// Data           :   ebp Relative, [00000008], Local, Type: int, nChannelID
// Data           :   ebp Relative, [FFFFFF90], Local, Type: struct ArPosition, pos
// Data           :   ebp Relative, [FFFFFFFC], Local, Type: struct StructSummon *, pSummon
// Data           :   ebp Relative, [FFFFFFA0], Local, Type: struct ArPosition, pos


            ArPosition pos;
            ArPosition result;
            Summon pSummon;
            int nChannelID;
            uint ct = Globals.GetArTime();

            if (pPlayer.GetSID() != 0 && pPlayer.GetName().Length > 0)
            {
                ServerLog.Log((ushort)0xA8D,pPlayer.GetAccountID(),pPlayer.GetSID(),0,0,pPlayer.m_layer,layer,(long)pPlayer.mv.x, (long)pPlayer.mv.y,
                    (long)pPosition.x, (long)pPosition.y,0,pPlayer.GetAccountName(),pPlayer.GetName(),"","");
                nChannelID = ChannelManager.GetChannelId(pPosition.x, pPosition.y);
                if (layer != pPlayer.m_layer)
                {
                    if (ChannelManager.GetChannelId(pPlayer.mv.x, pPlayer.mv.y) != 0 && pPlayer.m_layer != 0)
                        ChannelManager.LeavePlayerFromLayer(pPlayer.m_layer);
                    if (nChannelID != 0 && layer != 0)
                        ChannelManager.EnterPlayerToLayer(layer);
                }
                pPlayer.SetCurrentXY(pPosition.x, pPosition.y);
                pPlayer.m_layer = layer;
                pPlayer.StopMove();
                pPlayer.m_bWarpEnded = true;
                Messages.SendWarpMessage(pPlayer);

                if (pPlayer.m_pMainSummon != null)
                {
                    warpEndSummon(pPlayer, pPosition, layer, pPlayer.m_pMainSummon, ChannelManager.GetChannelType(nChannelID) == 2);
                }

                if (pPlayer.m_pSubSummon != null)
                {
                    warpEndSummon(pPlayer, pPosition, layer, pPlayer.m_pSubSummon, ChannelManager.GetChannelType(nChannelID) == 2);
                }

                if (pPlayer.m_pSummonedPet != null)
                {
                    pPlayer.m_pSummonedPet.SetCurrentXY(pPosition.x, pPosition.y);
                    pPlayer.m_pSummonedPet.m_layer = layer;
                    pPlayer.m_pSummonedPet.StopMove();
                    pPlayer.m_pSummonedPet.m_StatusFlag |= Creature.StatusFlags.FirstEnter;
                    pPlayer.m_pSummonedPet.AddNoise(Globals.GetRandomInt32(), Globals.GetRandomInt32(), 70);

                    RappelzServer.Instance.AddObject(pPlayer.m_pSummonedPet);
                    pPlayer.m_pSummonedPet.m_StatusFlag &= ~Creature.StatusFlags.FirstEnter;
                    pos = pPlayer.m_pSummonedPet.GetCurrentPosition(ct);
                    RappelzServer.Instance.SetMove(pPlayer.m_pSummonedPet, pos, pos, 0, true, ct, true);
                }
                pPlayer.m_StatusFlag |= Creature.StatusFlags.Invincible;

                if (pPlayer.m_pMainSummon != null)
                    pPlayer.m_pMainSummon.m_StatusFlag |= Creature.StatusFlags.Invincible;

                if (pPlayer.m_pSubSummon != null)
                    pPlayer.m_pSubSummon.m_StatusFlag |= Creature.StatusFlags.Invincible;
                pPlayer.m_StatusFlag |= Creature.StatusFlags.FirstEnter;

                RappelzServer.Instance.AddObject(pPlayer);
                pPlayer.m_StatusFlag &= ~Creature.StatusFlags.FirstEnter;
                pos = pPlayer.GetCurrentPosition(ct);
                RappelzServer.Instance.SetMove(pPlayer, pos, pos, 0, true, ct, true);
                Messages.SendPropertyMessage(pPlayer, pPlayer.m_hHandle, "channel", ChannelManager.GetChannelNum(layer));
                if (nChannelID != 0 && ChannelManager.GetChannelType(nChannelID) == 2 && (pPlayer.m_nRideIdx != 0 || pPlayer.m_nRidingStateUid != 0))
                    pPlayer.UnMount(0);
                pPlayer.ChangeLocation(pPlayer.mv.x,pPlayer.mv.y, false, true);
                pPlayer.Save(true);
            }
        }

        public static void warpEndSummon(Player pPlayer, ArPosition pPosition, byte layer, Summon pSummon, bool bInDungeon)
        {
            ArPosition pos;

            uint ct = Globals.GetArTime();

            if (pSummon != null && pSummon.m_bIsSummoned)
            {
                pSummon.SetCurrentXY(pPosition.x, pPosition.y);
                pSummon.m_layer = layer;
                pSummon.StopMove();
                pSummon.m_StatusFlag |= Creature.StatusFlags.FirstEnter;
                if (pSummon != pPlayer.GetRideObject())
                {
                    pSummon.AddNoise(Globals.GetRandomInt32(), Globals.GetRandomInt32(), 70);
                }

                RappelzServer.Instance.AddObject(pSummon);
                pSummon.m_StatusFlag &= ~Creature.StatusFlags.FirstEnter;

                pos = pSummon.GetCurrentPosition(ct);
                RappelzServer.Instance.SetMove(pSummon, pos,pos, 0, true, ct, true);
                if (bInDungeon && GameRule.bLimitDungeonEnterableLevel)
                {
                    if (pSummon.GetLevel() > pPlayer.GetLevel())
                        pPlayer.PendUnSummon(pSummon);
                }
            }
        }

        public static bool checkQuestTypeFlag(QuestBase.QuestType type, int flag)
        {
            switch(type)
            {
                case QuestBase.QuestType.Misc:
                    return (flag & 1) != 0;

                case QuestBase.QuestType.KillTotal:
                    return (flag & 2) != 0;

                case QuestBase.QuestType.KillIndividual:
                    return (flag & 4) != 0;

                case QuestBase.QuestType.Collect:
                    return (flag & 8) != 0;

                case QuestBase.QuestType.HuntItem:
                    return (flag & 0x10) != 0;

                case QuestBase.QuestType.HuntItemFromAnyMonsters:
                    return (flag & 0x1000) != 0;

                case QuestBase.QuestType.LearnSkill:
                    return (flag & 0x20) != 0;

                case QuestBase.QuestType.UpgradeItem:
                    return (flag & 0x40) != 0;

                case QuestBase.QuestType.Contact:
                    return (flag & 0x80) != 0;

                case QuestBase.QuestType.JobLevel:
                    return (flag & 0x100) != 0;

                case QuestBase.QuestType.Parameter:
                    return (flag & 0x200) != 0;

                case QuestBase.QuestType.RandomKillIndividual:
                    return (flag & 0x400) != 0;

                case QuestBase.QuestType.RandomCollect:
                    return (flag & 0x800) != 0;

            }

            return false;
        }

        public static int isLearnableSkill(Creature pCreature, int skill_id, int skill_level, int nJobId, int creature_job_level)
        {
            bool bMaxLimit = false;
            bool bFound = false;

            List<SkillTree> st = getSkillTree(nJobId);

            if (st != null)
            {
                if (st.Count > 0)
                {
                    foreach (SkillTree stree in st)
                    {
                        if (stree.skill_id == skill_id)
                        {
                            if (stree.max_skill_lv >= skill_level)
                            {
                                if (stree.lv > pCreature.GetLevel())
                                {
                                    return 13;
                                }
                                if (stree.job_lv <= creature_job_level)
                                {
                                    for(int nsi = 0; nsi < 3; nsi++)
                                    {
                                        if (stree.need_skill_id[nsi] == 0)
                                            break;

                                        if (pCreature.GetCurrentSkillLevel(stree.need_skill_id[nsi]) < stree.need_skill_lv[nsi])
                                        {
                                            return 15;
                                        }
                                    }

                                    SkillBase sb = GameContent.GetSkillBase(skill_id);
                                    if (sb == null)
                                        return 6;

                                    if (pCreature.GetJobPoint() < (int)((float)sb.GetNeedJobPoint(skill_level) * stree.jp_ratio))
                                    {
                                        return 12;
                                    }
                                    return 0;
                                }
                                bFound = true;
                            }
                            else
                            {
                                bMaxLimit = true;
                            }
                        }
                    }
                    if (bFound)
                    {
                        return 14;
                    }
                    if ( bMaxLimit )
                    {
                        return 16;
                    }
                }
            }
            return 6;
        }


        public static List<SkillTree> getSkillTree(int job_id)
        {
            List<SkillTree> skills = new List<SkillTree>();

            foreach (SkillTreeGroup stg in g_vSkillTree)
            {
                if (stg.job_id == job_id)
                {
                    foreach (SkillTree st in stg.skillTrees)
                    {
                        skills.Add(st);
                    }
                }
            }
            return skills;
        }


        public static void MonsterDropItemToWorld(Creature pCreature, Item pItem)
        {
            PacketOut pak = new PacketOut(ClientOutPackets.ItemDrop);
            pak.WriteUInt32(pCreature.m_hHandle);
            pak.WriteUInt32(pItem.m_hHandle);

            RappelzServer.Instance.Broadcast((uint)(pItem.mv.x / GameContent.g_nRegionSize), (uint)(pItem.mv.y / GameContent.g_nRegionSize), pItem.m_layer, pak);
            AddItemToWorld(pItem);
        }


        public static void AddItemToWorld(Item pItem)
        {
            RappelzServer.Instance.AddObject(pItem);
            pItem.m_nDropTime = Globals.GetArTime();

            ItemCollector.Instance.RegisterItem(pItem);
        }

        public static bool checkDrop(Creature pKiller, int code, int percentage, float fDropRatePenalty, float fPCBangDropRateBonus)
        {
            float fMod;
            float fCreatureCardMod;

            fCreatureCardMod = 1.0f;
            fMod = pKiller.GetItemChance() * 0.01f + 1.0f;
            if (code > 0)
            {
                if (Item.GetItemBase(code).nGroup == 13)
                    fCreatureCardMod = pKiller.m_fCreatureCardChance;
                if ((Item.GetItemBase(code).Flag & 0x800) != 0)
                    fDropRatePenalty = 1.0f;
            }
            return percentage * fMod * GameRule.fItemDropRate * fDropRatePenalty * fPCBangDropRateBonus * fCreatureCardMod >= Globals.GetRandomInt32(1, 100000000);
        }

        public static uint procAddItem(Player pClient, Item pItem, bool bIsPartyProcess)
        {
            long uid;                      
            int code;                      
            Item pNewItem;                 
            uint item_handle;
 
            code = pItem.m_Instance.Code;
            if (code != 0 || (pClient.m_nGold + pItem.m_Instance.nCount) < Constants.MAX_GOLD_FOR_INVENTORY)
            {
                pItem.m_Instance.nIdx = 0;
                pItem.m_bIsNeedUpdateToDB = true;
                pNewItem = pClient.PushItem(pItem, pItem.m_Instance.nCount, false);

                if (pItem.m_bIsEventDrop)
                {
                    pItem.m_bIsEventDrop = false;
                    pItem.m_Instance.Flag = 0;

//                    Globals.Log.Debug("Event --- %20s\t%20u\t%20d\t%20u", v12, v11, v10, v9);
                    if (GameRule.bBroadcastEventItemPickup)
                    {
                        Messages.PrintfGlobalChatMessage(20, "@NOTICE", "@955\v#@picker_name@#\v%s\v#@item_name@#\v@%d", pClient.GetName(), pItem.m_pItemBase.nNameId);
                    }
                }
                if (pNewItem != null)
                    uid = pNewItem.m_Instance.UID;
                else
                    uid = 0;

                if (pNewItem != null)
                    item_handle = pNewItem.m_hHandle;
                else
                    item_handle = pItem.m_hHandle;

                if (pItem.m_Instance.Code != 0)
                {
                    // a real item
                    ServerLog.Log((ushort)0x961,pClient.GetAccountID(), pClient.GetSID(),pItem.m_Instance.nLevel + 100 * pItem.m_Instance.nEnhance,
                        code, pItem.m_Instance.nCount, pNewItem != null ? pNewItem.m_Instance.nCount : 0, 0,0,
                        (long)pClient.mv.x,(long)pClient.mv.y,uid,pClient.GetAccountName(),pClient.GetName(),"",bIsPartyProcess ? "PPICK" : "PICK");
                }
                else
                {
                    // gold
                    ServerLog.Log((ushort)0x961,pClient.GetAccountID(), pClient.GetSID(),pItem.m_Instance.nLevel + 100 * pItem.m_Instance.nEnhance,
                        code, 0,0,pItem.m_Instance.nCount,pClient.m_nGold,
                        (long)pClient.mv.x,(long)pClient.mv.y,uid,pClient.GetAccountName(),pClient.GetName(),"",bIsPartyProcess ? "PPICK" : "PICK");
                }
                if (pNewItem != null)
                {
                    if (!ReferenceEquals(pNewItem,pItem))
                        Item.PendFreeItem(pItem);
                }
            }
            else
            {
                item_handle = 0;
            }
            return item_handle;
        }

        public static bool RemoveItemFromWorld(Item pItem)
        {
            bool result;

            result = ItemCollector.Instance.UnregisterItem(pItem);
            if ( result )
            {
                RappelzServer.Instance.RemoveObject(pItem);
                pItem.m_nDropTime = 0;
                result = true;
            }
            return result;
        }

        public static void procPartyShare(Player pClient, Item pItem)
        {

        }

        public static SummonBase GetSummonInfo(int summon_id)
        {
            if (g_hsSummonInfo.ContainsKey(summon_id))
                return g_hsSummonInfo[summon_id];
            return new SummonBase();
        }

        public static void AddSkillResult(List<SkillResult> pvList, bool bIsSuccess, int nSuccessType, uint handle)
        {
            SkillResult skill_result = new SkillResult();
            skill_result.type = (int)SkillResult.ResultType.Result;
            skill_result.hTarget = handle;
            skill_result.result = new SkillResult.Result();
            skill_result.result.bResult = bIsSuccess;
            skill_result.result.success_type = nSuccessType;

//             sk
//             *&skill_result.___u0.damage.damage_type = 0i64; // 9
//             *(&skill_result.___u0.damage.elemental_damage[1] + 1) = 0; // 12
//             *(&skill_result.___u0.damage.flag + 3) = 0;
//             LOBYTE(skill_result.___u0.damage.target_hp) = bIsSuccess;
//             skill_result.___u0.damage.hTarget = handle;
//             *(&skill_result.___u0.damage.target_hp + 1) = nSuccessType;
//             skill_result.___u0.damage.type = 10;
            pvList.Add(skill_result);
        }

        public static void AddSkillDamageResult(List<SkillResult> pvList, bool bIsSuccess, int nSuccessType, uint handle)
        {
            SkillResult skill_result = new SkillResult();
            skill_result.type = (int)SkillResult.ResultType.Result;
            skill_result.hTarget = handle;
            skill_result.result = new SkillResult.Result();
            skill_result.result.bResult = bIsSuccess;
            skill_result.result.success_type = nSuccessType;

            //             sk
            //             *&skill_result.___u0.damage.damage_type = 0i64; // 9
            //             *(&skill_result.___u0.damage.elemental_damage[1] + 1) = 0; // 12
            //             *(&skill_result.___u0.damage.flag + 3) = 0;
            //             LOBYTE(skill_result.___u0.damage.target_hp) = bIsSuccess;
            //             skill_result.___u0.damage.hTarget = handle;
            //             *(&skill_result.___u0.damage.target_hp + 1) = nSuccessType;
            //             skill_result.___u0.damage.type = 10;
            pvList.Add(skill_result);
        }
        public static void AddSkillDamageResult(List<SkillResult> pvList, byte type, byte damage_type, Creature.DamageInfo damage_info, uint handle)
        {
            SkillResult skill_result = new SkillResult();
            skill_result.type = type;

            skill_result.hTarget = handle;
            skill_result.damage = new SkillResult.Damage();
            skill_result.damage.damage_type = 0;
            skill_result.damage.damage_type = damage_type;

            skill_result.damage.flag = 0;
            if (damage_info.bCritical)
                skill_result.damage.flag = 1;
            if ( damage_info.bBlock )
                skill_result.damage.flag |= 4;
            if ( damage_info.bMiss )
                skill_result.damage.flag |= 2;
            if ( damage_info.bPerfectBlock )
                skill_result.damage.flag |= 8;
            skill_result.damage.damage = damage_info.nDamage;
            skill_result.hTarget = handle;
            skill_result.damage.target_hp = damage_info.target_hp;
            skill_result.damage.elemental_damage[0] = damage_info.elemental_damage[0];
            skill_result.damage.elemental_damage[1] = damage_info.elemental_damage[1];
            skill_result.damage.elemental_damage[2] = damage_info.elemental_damage[2];
            skill_result.damage.elemental_damage[3] = damage_info.elemental_damage[3];
            skill_result.damage.elemental_damage[4] = damage_info.elemental_damage[4];
            skill_result.damage.elemental_damage[5] = damage_info.elemental_damage[5];
            skill_result.damage.elemental_damage[6] = damage_info.elemental_damage[6];

            pvList.Add(skill_result);
        }


        public static bool SetTamer(Monster pMonster, Player pPlayer, int nSkillLevel)
        {
            bool result;

            if (pPlayer.m_hTamingTarget != 0)
            {
                result = false;
            }
            else
            {
                int tameCode = pMonster.GetTameItemCode();
                if (pMonster.m_nHP == pMonster.m_nMaxHP
                  && pMonster.GetTamer() == 0
                  && tameCode != 0)
                {
                    Item card = pPlayer.FindEmptySummonCard(tameCode);
                    if (card != null)
                    {
                        pMonster.SetTamer(pPlayer.m_hHandle, nSkillLevel);
                        pPlayer.m_hTamingTarget = pMonster.m_hHandle;
                        card.m_Instance.Flag |= 0x20000000;
                        Messages.BroadcastTamingMessage(pPlayer, pMonster, 0);
                        result = true;
                    }
                    else
                    {
                        result = true;
                    }
                }
                else
                {
                    result = false;
                }
            }
            return result;
        }

        public static void RegisterSummonUniqueName(int summon_type, int id)
        {
//             if (summon_type <= 9)
//                 std::vector<StructRoamer___std::allocator<StructRoamer__>>::push_back(&g_avSummonUniqueName[summon_type], &id);
        }

        public static void RegisterSummonDefaultName(int id, bool bIsPrefix)
        {
            List<int> l = g_vSummonPrefix;
            if ( !bIsPrefix )
                g_vSummonPostFix.Add(id);
            else
                g_vSummonPrefix.Add(id);
        }

        public static void RegisterBlockInfo(X2D.PolygonF block_info)
        {
            if(g_qtBlockInfo == null)
            {
                g_qtBlockInfo = new X2D.QuadTreeMapInfo(GameContent.g_nMapWidth,GameContent.g_nMapHeight);
            }
            g_qtBlockInfo.Add(block_info);
        }

        public static void RegisterAutoCheckBlockInfo(X2D.PolygonF block_info)
        {
            if(g_qtAutoCheckBlockInfo == null)
            {
                g_qtAutoCheckBlockInfo = new X2D.QuadTreeMapInfo(GameContent.g_nMapWidth,GameContent.g_nMapHeight);
            }
            g_qtAutoCheckBlockInfo.Add(block_info);
        }


        public static string GetSummonName()
        {
            string res;
            int i = Globals.GetRandomInt32(0, g_vSummonPrefix.Count-1);
            res = GameContent.GetString(g_vSummonPrefix[i]);
            i = Globals.GetRandomInt32(0, g_vSummonPostFix.Count-1);
            res += GameContent.GetString(g_vSummonPostFix[i]);
            return res;
        }

        public static string GetUniqueName(int summon_type)
        {
//             if ( summon_type > 9 )
//             {
//                 std::basic_string<char_std::char_traits<char>_std::allocator<char>>::basic_string<char_std::char_traits<char>_std::allocator<char>>(
//                     result,
//                     &unk_5F42BB);
//             }
//             else
//             {
//                 v2 = std::vector<KHash<RankingManager::_RANKING_DATA___khash_def::hashPr_mod_basic<int>>::node___std::allocator<KHash<RankingManager::_RANKING_DATA___khash_def::hashPr_mod_basic<int>>::node__>>::size(&g_avSummonUniqueName[summon_type]);
//                 v3 = XFastRandom();
//                 v4 = std::vector<XLinearMemoryPool___std::allocator<XLinearMemoryPool__>>::operator__(
//                          &g_avSummonUniqueName[summon_type],
//                          v3 % v2);
//                 v5 = GameContent::GetString(*v4);
//                 std::basic_string<char_std::char_traits<char>_std::allocator<char>>::basic_string<char_std::char_traits<char>_std::allocator<char>>(
//                     result,
//                     v5);
//             }
//             return result;
            return GetSummonName();
        }

        public static bool IsAllowedCommand(int nPermission, string pszCommand, string pszParameter)
        {
            if(nPermission >= 100)
                return true;

            lock(g_vAllowedCommandsList)
            {
                foreach (AllowedCommandInfo aci in g_vAllowedCommandsList)
                {
                    if(aci.nPermisson == nPermission)
                    {
                        foreach (AllowedCommandInfo.CommandInfo ci in aci.vCommandInfoList)
                        {
                            if(ci.szCommand == pszCommand && ci.szParameter == pszParameter)
                                return true;
                        }
                    }
                }

            }
            return false;
        }

        public static bool IsBannedWord(string szString)
        {
            return false;
        }

        public static Monster respawnMonster(uint x, uint y, byte layer, uint id, bool is_wandering, int way_point_id, IMonsterDeleteHandler pDeleteHandler, bool bNeedLock)
        {
            Monster mob = Monster.AllocMonster(id);
            if (mob != null)
            {
                mob.m_nGenerateCode = 1;
                mob.SetCurrentXY(x, y);
                mob.m_layer = layer;
                mob.m_bIsWandering = is_wandering;
                mob.m_pDeleteHandler = pDeleteHandler;
                if (way_point_id != 0)
                    mob.m_pWayPointInfo = GameContent.GetWayPoint(way_point_id);
                //                ArcadiaAutoLock::ArcadiaAutoLock((v8 - 36));
                if (bNeedLock)
                {
                    //                    v16 = RappelzServer.Instance._LockObjectWithVisibleRange((v8 - 16), mob);
                    //                    ArcadiaAutoLock::set(bNeedLock,v16,);
                }
                GameContent.AddMonsterToWorld(mob);
                if (way_point_id != 0)
                {
                    RappelzServer.Instance.SetObjectPriority(mob, SchedulerObject.Priority.Normal);
                }
                Interlocked.Increment(ref GameContent.g_nRespawnCnt);
                //                ArcadiaAutoLock::_ArcadiaAutoLock((v8 - 36));
            }
            return mob;
        }

        public static void SetWayPointType(int way_point_id, int way_point_type)
        {
            foreach (WayPointInfo wpi in g_vWayPoint)
            {
                if(wpi.way_point_id == way_point_id)
                    return;
            }

            WayPointInfo info = new WayPointInfo();
            info.way_point_speed = 0;
            info.way_point_type = way_point_type;
            info.way_point_id = way_point_id;
            g_vWayPoint.Add(info);
        }

        public static void AddWayPoint(int way_point_id, float x, float y)
        {
            ArPosition pos = new ArPosition(x,y,0);

            foreach (WayPointInfo wpi in g_vWayPoint)
            {
                if(wpi.way_point_id == way_point_id)
                {
                    wpi.vWayPoint.Add(pos);
                    return;
                }
            }

            WayPointInfo info = new WayPointInfo();
            info.way_point_speed = 0;
            info.way_point_type = 1;
            info.way_point_id = way_point_id;
            info.vWayPoint.Add(pos);
            g_vWayPoint.Add(info);
        }

        public static WayPointInfo GetWayPoint(int way_point_id)
        {
            foreach (WayPointInfo wpi in g_vWayPoint)
            {
                if(wpi.way_point_id == way_point_id)
                    return wpi;
            }
            return null;
        }

        public static int EnumSkillTargetsAndCalcDamage(ArPosition _OriginalPos, byte layer, ArPosition _TargetPos, bool bTargetOrigin, float fEffectLength, int nRegionType, float fRegionProperty, int nOriginalDamage, bool bIncludeOriginalPos, Creature pCaster, int nDistributeType, int nTargetMax, List<Creature> vTargetList, bool bEnemyOnly)
        {
            DirectionRegionTester RegionTester_Direction;       // -196 -0C4h
            CrossRegionTester RegionTester_Cross;               // -156 -9Ch
            ArcCircleRegionTester RegionTester_ArcCircle;       // -120 -78h
            ArPosition current_pos;                             // -96  -60h
            CircleRegionTester RegionTester_Circle;             // -72  -48h
// .text:004C9876 itRawTargetList = std::_Vector_iterator<unsigned int,std::allocator<unsigned int> > ptr -68   -44h
            Creature pTarget;                                   // -60  -3Ch
            int nResult;                                        // -56  -38h
            List<uint> vList = new List<uint>();                // -52  -34h
// .text:004C9876 var_24          = dword ptr -24h
// .text:004C9876 var_18          = dword ptr -18h
            int nTargetCount;                                   // -16  -10h
            bool bIsAlly;                                       // 23   17h
            int nAllyCount;                                     // 28   1Ch

// .text:004C9876 _OriginalPos    = dword ptr           8   08h
// .text:004C9876 layer           = byte ptr            12  0Ch
// .text:004C9876 _TargetPos      = dword ptr           16  10h
// .text:004C9876 bTargetOrigin   = byte ptr            20  14h
// .text:004C9876 fEffectLength   = dword ptr           24  18h
// [0000001C], Param, Type: const int, nRegionType      28  1Ch                        
// .text:004C9876 fRegionProperty = dword ptr           32  20h
// .text:004C9876 nOriginalDamage = dword ptr           36  24h
// .text:004C9876 bIncludeOriginalPos= byte ptr         40  28h
// .text:004C9876 pCaster         = dword ptr           44  2Ch
// .text:004C9876 nDistributeType = dword ptr           48  30h
// .text:004C9876 nTargetMax      = dword ptr           52  34h
// .text:004C9876 vTargetList     = dword ptr           56  38h
// .text:004C9876 bEnemyOnly      = byte ptr            60  3Ch

// Data           :   ebp Relative, [FFFFFFCC], Local, Type: class std::vector<unsigned int,std::allocator<unsigned int> >, vList
            ArPosition rOriginalPos;        // 20
            ArPosition rTargetPos;          // -28
            RegionTester regionTest = null;
            
            nResult = nOriginalDamage;
            rOriginalPos = _TargetPos;
            if (!bTargetOrigin)
                rOriginalPos = _OriginalPos;

            rTargetPos = _OriginalPos;
            if (!bTargetOrigin)
                rTargetPos = _TargetPos;

            RappelzServer.Instance.EnumMovableObject(rOriginalPos, layer, fEffectLength, vList, true, true);
//            v22 = vTargetList;
            vTargetList.Clear();
//            v23 = vList.Count;

            switch(nRegionType)
            {
                case 0:
                    regionTest = new DirectionRegionTester();
                    break;

                case 1:
                    regionTest = new ArcCircleRegionTester();
                    break;

                case 2:
                    regionTest = new CrossRegionTester();
                    break;

                default:
                    regionTest = new CircleRegionTester();
                    break;
            }

            regionTest.Init(rOriginalPos, rTargetPos, fRegionProperty); // may need to swap these

            nTargetCount = 0;
            nAllyCount = 0;

            foreach(uint uid in vList)
            {
                bIsAlly = false;
                Creature cr = Creature.get(uid) as Creature;
                if (cr != null)
                {
                    if (cr.IsCreature())
                    {
                        if (!cr.IsPet())
                        {
                            if (cr.m_nHP != 0)
                            {
                                if (!pCaster.IsEnemy(cr, true))
                                {
                                    if (bEnemyOnly)
                                        continue;
                                    bIsAlly = true;
                                }

                                current_pos = cr.GetCurrentPosition(Globals.GetArTime());
                                if (regionTest.IsInRegion(current_pos))
                                {
                                    if (bIncludeOriginalPos || !rOriginalPos.IsEqual(current_pos))
                                    {
                                        if (bIsAlly)
                                        {
//                                             std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                                                 (v14 - 36),
//                                                 *(v22 + 4),
//                                                 v22);
//                                             v29.baseclass_0._Myptr = *(v14 - 32);
//                                             v29.baseclass_0.baseclass_0.baseclass_0._Mycont = *(v14 - 36);
//                                             std::vector<GameContent::HUNTAHOLIC_INFO___std::allocator<GameContent::HUNTAHOLIC_INFO__>>::insert(
//                                                 v22,
//                                                 (v14 - 80),
//                                                 v29,
//                                                 ct);
                                            ++nAllyCount;
                                        }
                                        else
                                        {
                                            vTargetList.Add(cr);
                                            ++nTargetCount;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (nDistributeType == 3)
            {
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     (v14 - 36),
//                     *(v22 + 8),
//                     v22);
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     (v14 - 24),
//                     *(v22 + 4),
//                     v22);
//                 v32 = std::_Vector_iterator<KHash<_MARKET_INFO___khash_def::hashPr_str<khash_def::string_tr_khash_def::nocase_tr>>::node___std::allocator<KHash<_MARKET_INFO___khash_def::hashPr_str<khash_def::string_tr_khash_def::nocase_tr>>::node__>>::operator_(
//                           (v14 - 24),
//                           (v14 - 80),
//                           *(v14 + 28));
//                 v33.baseclass_0._Myptr = *(v14 - 32);
//                 v33.baseclass_0.baseclass_0.baseclass_0._Mycont = *(v14 - 36);
//                 std::sort<std::_Vector_iterator<StructCreature___std::allocator<StructCreature__>>_lessByDistantFromTarget>(
//                     *&v32->baseclass_0.baseclass_0.baseclass_0._Mycont,
//                     v33,
//                     *(v14 + 16));
//                if (nTargetCount > nTargetMax)
//                    Array.Resize(ref vTargetList, nTargetMax + nAllyCount);
            }
            if (nDistributeType == 4)
            {
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     (v14 - 36),
//                     *(v22 + 8),
//                     v22);
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     (v14 - 24),
//                     *(v22 + 4),
//                     v22);
//                 v34 = std::_Vector_iterator<KHash<_MARKET_INFO___khash_def::hashPr_str<khash_def::string_tr_khash_def::nocase_tr>>::node___std::allocator<KHash<_MARKET_INFO___khash_def::hashPr_str<khash_def::string_tr_khash_def::nocase_tr>>::node__>>::operator_(
//                           (v14 - 24),
//                           (v14 - 80),
//                           *(v14 + 28));
//                 v35.baseclass_0._Myptr = *(v14 - 32);
//                 v35.baseclass_0.baseclass_0.baseclass_0._Mycont = *(v14 - 36);
//                 std::sort<std::_Vector_iterator<StructCreature___std::allocator<StructCreature__>>_lessByDistantFromTarget>(
//                     *&v34->baseclass_0.baseclass_0.baseclass_0._Mycont,
//                     v35,
//                     *(v14 + 8));
            }
            if (nDistributeType == 2 || nDistributeType == 4)
            {
//                if (nTargetCount > nTargetMax)
//                    List.Resize(ref vTargetList, nTargetMax + nAllyCount);
            }
            if (nDistributeType == 1 )
            {
                if (nTargetCount > nTargetMax)
                    nResult = nTargetMax * nOriginalDamage / nTargetCount;
            }
            return nResult;
        }

    }
}
